C和C ++之间的字符串文字差异

据我所知,在C ++ 11之前,字符串文字在C和C ++之间几乎完全相同。

现在,我承认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] */ 

而技术上的差异只在C ++中很重要。 在C ++中, "abc"const char [4]而在C中它是char [4] 。 但是,C ++有一个特殊的规则,允许转换为const char * ,然后转换为char *以保持C兼容性,直到C ++ 11不再应用该特殊规则时。

文字允许长度的差异。 但是,实际上任何编译C和C ++代码的编译器都不会强制执行较低的C限制。

我有一些有趣的链接适用:

  • http://david.tribble.com/text/cdiffs.htm
  • http://www.coding-guidelines.com/cbook/c90c++.pdf

还有其他差异吗?

原始字符串

一个明显的区别是C ++的字符串文字是C语言的超集。 具体来说,C ++现在支持原始字符串 (C中不支持 ),技术上定义为§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") 

现场演示


char vs const char

注释中指出的另一个区别是字符串文字在C中具有char [n]类型,如§6.4.5/ 6中所述:

对于字符串文字,数组元素的类型为char,并使用多字节字符序列的各个字节进行初始化。

而在C ++中,它们具有类型const char [n] ,如§2.14.5/ 8中所定义:

普通字符串文字和UTF-8字符串文字也称为窄字符串文字。 窄字符串文字的类型为“n const char数组”,其中n是下面定义的字符串大小,并且具有静态存储持续时间(3.7)。

这并没有改变这两个标准(分别为C和C ++的§6.4.5/ 7和2.14.5 / 13)尝试修改字符串文字导致未定义行为的事实。


未指定与实施定义( 参考 )

另一个细微的区别是,在C中,字符串文字的字符数组是不同的是未指定的,如§6.4.5/ 7所示:

如果这些数组的元素具有适当的值,则这些数组是否不同是未指定的。

而在C ++中,这是实现定义,根据§2.14.5/ 13:

是否所有字符串文字都是不同的(即存储在非重叠对象中)是实现定义的。

回答问题的最佳方法是将其重写为在使用“C”或“C ++”编译器时编译相同的程序,我假设您正在使用GCC,但其他( 正确编写的 )编译器工具链应该提供类似的结果。

首先,我将解决您提出的每一点,然后我将提供一个程序,提供答案(和certificate)。

  • 据我所知,在C ++ 11之前,字符串文字在C和C ++之间几乎完全相同。

它们仍然可以使用各种命令行参数以相同的方式处理,在本例中我将使用“-fpermissive”(作弊)。 你最好找出为什么你会收到警告并编写新代码以避免任何警告; 只使用CLP’作弊’来编译OLD代码。

正确编写新代码 (没有作弊和没有警告,没有错误就不用说了)。

  • 现在,我承认C和C ++在处理宽字符串文字方面存在差异。

没有(很多差异),因为你可以根据具体情况欺骗大部分或全部。 作弊是错误的,学会正确编程并遵循现代标准,而不是过去的错误(或尴尬)。 在某些情况下,事情以某种方式对您和编译器都有帮助(请记住,您并不是唯一一个’看到’您的代码的人)。

这种情况下,编译器需要分配足够的空间来终止带有’0’(零字节)的String。 这允许使用print(和其他一些)函数而不指定String的长度。

如果你只是想编译你从某个地方获得的现有程序并且不想重写它,你只需要编译并运行它,然后使用作弊(如果你必须)通过警告和强制编译成可执行文件。

  • 你写的其余部分……

没有。

请参阅此示例程序。 我稍微修改了你的问题,使其成为一个程序。 使用“C”或C ++“编译器编译本程序的结果是相同的。

将下面的示例程序文本复制并粘贴到名为“test.c”的文件中,然后按照开头的说明进行操作。 只需“捕捉”文件,这样您就可以在不打开文本编辑器的情况下对其进行反向滚动(并查看),然后从“编译器命令”(接下来的三个)开始复制并粘贴每一行。

注意,正如注释中所指出的,运行此行“g ++ -S -o test_c ++。s test.c”会产生错误(使用现代g ++编译器),因为容器不足以容纳String。

您应该能够阅读本程序,而不是实际需要编译它以查看答案,但它会编译并生成输出供您检查,如果您希望这样做。

正如您所看到的,Varable“str1”不足以在String终止时保存String,这会在现代(并且正确编写)的g ++编译器上产生错误。


 /* Answer for: http://stackoverflow.com/questions/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" * */