Строковые литературные различия между 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"
 *
 */