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

时间:2014-04-18 00:53:28

标签: 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] */

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

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

我有一些有用的链接:

是否存在其他差异?

2 个答案:

答案 0 :(得分:8)

原始字符串

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

评论中指出的另一个不同之处是,字符串文字在C中的类型为char [n],如§6.4.5/ 6所述:

  

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

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

  

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

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


未指定与实施定义(ref

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

  

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

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

  

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

答案 1 :(得分:-1)

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

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

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

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

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

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

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

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

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

  • 你写的其余部分......

没有

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

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

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

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

你可以看到Varable&#34; str1&#34;不足以在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"
 *
 */