Строковые литературные различия между C и С++
Насколько я могу судить, перед С++ 11 строковые литералы обрабатывались почти точно так же между C и С++.
Теперь я признаю, что существуют различия между C и С++ при обработке широких строковых литералов.
Единственные различия, которые я смог найти, - это инициализация массива строковым литералом.
char str[3] = "abc"; /* OK in C but not in C++ */
char str[4] = "abc"; /* OK in C and in C++. Terminating zero at str[3] */
И техническая разница, которая имеет значение только в С++. В С++ "abc"
есть const char [4]
, а в C - char [4]
. Однако у С++ есть специальное правило, которое позволяет преобразовать в const char *
, а затем в char *
, чтобы сохранить совместимость C до С++ 11, когда это специальное правило больше не применяется.
И разница в допустимых длинах литералов. Однако в практическом отношении любой компилятор, который компилирует код C и С++, не будет применять нижний предел C.
У меня есть интересные ссылки:
Есть ли другие отличия?
Ответы
Ответ 1
Необработанные строки
Заметное отличие состоит в том, что строковые литералы С++ являются надмножеством C-элементов. В частности, С++ теперь поддерживает необработанные строки (не поддерживается в C), технически определенный в п. 2.2.14.15 и обычно используемый в HTML и XML, где часто встречается "
.
Необработанные строки позволяют указать свой собственный разделитель (до 16 символов) в форме:
R"delimiter(char sequence)delimiter"
Это особенно полезно, чтобы избежать ненужных экранирующих символов, предоставляя свой собственный ограничитель строк. Следующие два примера показывают, как вы можете избежать экранирования "
и (
соответственно:
std::cout << R"(a"b"c")"; // empty delimiter
std::cout << '\n';
std::cout << R"aa(a("b"))aa"; // aa delimiter
// a"b"c"
// a("b")
Live demo
char
vs const char
Другая разница, отмеченная в комментариях, заключается в том, что строковые литералы имеют тип char [n]
в C, как указано в §6.4.5/6:
Для символьных строковых литералов элементы массива имеют тип char и инициализируются отдельными байтами многобайтовой последовательности символов.
тогда как в С++ они имеют тип const char [n]
, как определено в п. 2.2.14/8:
Обычные строковые литералы и строковые литералы UTF-8 также называются узкими строковыми литералами. Стрелка string literal имеет тип "array of n const char", где n - размер строки, как определено ниже, и имеет статическая продолжительность хранения (3.7).
Это не меняет того факта, что в обоих стандартах (в §6.4.5/7 и 2.14.5/13 для C и С++ соответственно) попытка изменения строкового литерала приводит к поведению undefined.
Определено неспециализированное vs Реализация (ref)
Еще одно тонкое различие заключается в том, что в C, поскольку массивы символов строковых литералов различны, не указано в соответствии с §6.4.5/7:
Неизвестно, являются ли эти массивы различными, если их элементы имеют соответствующие значения.
а в С++ - это реализация, определенная в соответствии с §2.14.5/13:
Определены ли все строковые литералы (то есть, хранятся в объектах с неперекрывающимися объектами).
Ответ 2
Лучший способ ответить на ваш вопрос - переписать его как программу, которая скомпилируется идентично при использовании компилятора "C" или "С++", я предполагаю, что вы используете GCC, но другие (правильно написанные) Компиляторы Toolchains должны обеспечивать аналогичные результаты.
Сначала я рассмотрю каждую поставленную вами точку, затем я дам Программу, которая дает ответ (и доказательство).
- Насколько я могу судить, перед С++ 11 строковые литералы обрабатывались почти точно так же между C и С++.
Они по-прежнему могут обрабатываться одинаково с использованием различных параметров командной строки, в этом примере я буду использовать "-fmpermissive" (Cheat). Вам лучше узнать, почему вы получаете предупреждения и пишите НОВЫЙ код, чтобы избежать ЛЮБОГО предупреждения; используйте CLP 'cheats' для компиляции OLD-кода.
Правильно напишите новый код (нет читов и нет предупреждений, что ошибок нет).
- Теперь я признаю, что существуют различия между C и С++ при обработке широких строковых литералов.
Не может быть (много различий), так как вы можете обманывать большинство или всех из них в зависимости от обстоятельств. Обман неправильный, научиться правильно программировать и следовать современным стандартам, а не ошибкам (или неловкости) прошлого. Все делается определенным образом, чтобы быть полезным как вам, так и компилятору в некоторых случаях (помните, что вы не единственный, кто "видит" ваш код).
В этом случае компилятор хочет достаточно места, выделенного для завершения строки String с помощью "0" (нулевой байт). Это позволяет использовать функцию печати (и некоторую другую) без указания длины строки.
ЕСЛИ вы просто пытаетесь скомпилировать существующую Программу, которую вы получили откуда-то, и не хотите ее переписывать, вы просто хотите ее скомпилировать и запустить, а затем использовать читы (если нужно), чтобы пройти мимо Предупреждения и принудительная компиляция исполняемого файла.
- Остальная часть того, что вы написали...
Нет.
.
См. пример программы. Я немного изменил ваш вопрос, чтобы превратить его в программу. Результат компиляции этой программы с помощью компилятора "C" или С++ идентичен.
Скопируйте и вставьте пример текста программы ниже в файл под названием "test.c", а затем следуйте инструкциям в начале. Просто "кота" в файле, чтобы вы могли его прокручивать (и видеть), не открывая текстовый редактор, а затем копировать и вставлять каждую строку, начинающуюся с команд компилятора (следующие три).
Обратите внимание, что, как указано в комментариях, эта строка "g++ -S -o test_С++. s test.c" создает ошибку (с использованием современного компилятора g++), так как контейнер недостаточно длинный, чтобы удерживать Строка.
Вы должны быть в состоянии прочитать эту Программу, и на самом деле не нужно ее компилировать, чтобы увидеть ответ, но он скомпилирует и произведет вывод для вас, если вы захотите это сделать.
Как вы можете видеть, Varable "str1" недостаточно длинный, чтобы удерживать String, когда он завершен с нулевой отметкой, что создает ошибку для современного (и правильно написанного) компилятора g++.
/* Answer for: http://stackoverflow.com/info/23145793/string-literal-differences-between-c-and-c
*
* cat test.c
* gcc -S -o test_c.s test.c
* g++ -S -o test_c++.s test.c
* g++ -S -fpermissive -o test_c++.s test.c
*
*/
char str1[3] = "1ab";
char str2[4] = "2ab";
char str3[] = "3ab";
main(){return 0;}
/* Comment: Executing "g++ -S -o test_c++.s test.c" produces this Error:
*
* test.c:10:16: error: initializer-string for array of chars is too long [-fpermissive]
* char str1[3] = "1ab";
* ^
*
*/
/* Resulting Assembly Language Output */
/* .file "test.c"
* .globl _str1
* .data
* _str1:
* .ascii "1ab"
* .globl _str2
* _str2:
* .ascii "2ab\0"
* .globl _str3
* _str3:
* .ascii "3ab\0"
* .def ___main; .scl 2; .type 32; .endef
* .text
* .globl _main
* .def _main; .scl 2; .type 32; .endef
* _main:
* LFB0:
* .cfi_startproc
* pushl %ebp
* .cfi_def_cfa_offset 8
* .cfi_offset 5, -8
* movl %esp, %ebp
* .cfi_def_cfa_register 5
* andl $-16, %esp
* call ___main
* movl $0, %eax
* leave
* .cfi_restore 5
* .cfi_def_cfa 4, 4
* ret
* .cfi_endproc
* LFE0:
* .ident "GCC: (GNU) 4.8.2"
*
*/