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

Zan*_*ynx 18 c c++ string string-literals

据我所知,在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] */
Run Code Online (Sandbox Code Playgroud)

技术差异只在C++中很重要.在C++ "abc"const char [4],它在C中char [4].然而,C++有一个特殊的规则,允许转化为const char *然后char *保留C兼容性直至C++ 11不再施加特殊规则时.

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

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

还有其他差异吗?

Sho*_*hoe 8

原始字符串

一个明显的区别是C++的字符串文字是C语言的超集.具体来说,C++现在支持原始字符串(C中不支持),在技术上定义为§2.14.15,并且通常在"经常遇到的HTML和XML中使用.

原始字符串允许您在表单中指定自己的分隔符(最多16个字符):

R"delimiter(char sequence)delimiter"
Run Code Online (Sandbox Code Playgroud)

这对于通过提供自己的字符串分隔符来避免不必要的转义字符特别有用.以下两个示例分别说明了如何避免转义"(:

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")
Run Code Online (Sandbox Code Playgroud)

Live demo


char VS const char

注释中指出的另一个区别是字符串文字char [n]在C中的类型,如§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:

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


小智 -1

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

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

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

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

正确编写新代码(没有作弊,没有警告,不言而喻,没有错误)。

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

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

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

如果您只是想编译从某处获得的现有程序并且不想重写它,您只是想编译并运行它,然后使用作弊(如果必须)来绕过警告并强制编译为可执行文件。

  • 剩下的你写的...

不。

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

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

请注意,正如注释中所指出的,运行“g++ -S -o test_c++.s test.c”这行会产生错误(使用现代 g++ 编译器),因为容器不够长,无法容纳字符串。

您应该能够阅读此程序,并且实际上不需要编译它来查看答案,但如果您愿意,它会编译并生成输出供您检查。

正如您所看到的,变量“str1”的长度不足以在以 null 结尾时保存字符串,这会在现代(且正确编写的)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"
 *
 */
Run Code Online (Sandbox Code Playgroud)

  • 很好的解释。但遗憾的是你错过了这个话题。 (4认同)
  • 他表示,OP 要求对他们进行额外的修改。你只是在解释他如何证明他所说的已经知道的事情。所以如果你问我那我就错过了这个话题。 (2认同)