【问题标题】:char four[4] = "four"; What are the correct semantics for this statement?char 四[4] = "四";该语句的正确语义是什么?
【发布时间】:2010-08-19 16:42:43
【问题描述】:
int main(void)
{
    char four[4] = "four";
    return 0;
}

编译为 C++ 程序时,G++ 报告

xxx.cpp: 在函数 int main():

xxx.cpp:3:错误:字符数组的初始化字符串太长

当编译一个 C 程序时,GCC 没有报错。

在我看来,正如我所料,赋值正确地将所有 4 个字节复制到变量中。

所以我的问题归结为.....

在 C 中观察到的行为是否正确,或者我是否在某处接触了未定义的行为, 还是完全是别的东西?

【问题讨论】:

标签: c++ c arrays initialization string-literals


【解决方案1】:

简短回答:您的代码是有效的 C,但不是有效的 C++。

长期回答:

"four" 实际上是 5 个字符长 - 那里为您添加了一个 \0。在 6.7.8 Initialization 部分的第 13 段中,C 标准说:

一个字符类型的数组可以由一个字符串字面量初始化,可选地用大括号括起来。字符串文字的连续字符(如果有空间或数组大小未知,则包括终止空字符)初始化数组的元素。

所以\0 在编译为 C 时会在您的程序中被忽略。C++ 对它的处理方式不同。事实上,这种特殊情况在 C++ 规范中明确被提及(第 8.5.2 字符数组,第 2 节):

初始化器的个数不得多于数组元素的个数。 [ 例子:

char cv[4] = "asdf";  // error

格式不正确,因为隐含的尾随 ’\0’ 没有空间。 — 结束示例 ]

【讨论】:

  • 在 C 中这是有效的,但它应该在某种程度上给你一个警告。
  • @Joel,我认为不应该有警告,标准似乎表明它是完全安全且定义明确的。
  • 虽然 sizeof("four") 是 5 个字节,但只有 4 个字节被复制到变量中。
  • @Carl:这是完全合法的,但它经常是一个错误并且可能导致问题(如strlen(four))。该标准不决定什么是完全安全的,只是定义明确的。我想看到一个警告。
  • 是的。我认为作为重写 charfour[4] = {'f', 'o', 'u', 'r'} 将是最合理的事情。这样不存在意图问题。
【解决方案2】:

字符串“four”实际上包含五个字节:四个字母加上一个零字节(\0)作为字符串终止符。自从我编写 C 或 C++ 以来已经有一段时间了,但我猜 C 编译器会出于某种原因默默地忽略它。

【讨论】:

    【解决方案3】:

    会更好

    char four[] = "four";
    

    【讨论】:

    • 在 C 和 C++ 中都提供了一个五字符数组,效果很好。
    • @David,仅当您想要一个五字符数组时。但如果你不在乎,这种方式肯定更易于维护。
    • 对,我认为你几乎不会想要 charfour[4] = "four"。
    • 我经常看到这样的事情。例如,如果您正在处理文件系统结构或可执行格式,那么文件中的各个位置通常都有 ASCII 标记。用于匹配磁盘数据的结构必须具有相同的布局,因此这些 ASCII 标记可能需要非空终止数组才能使一切有意义。过去,人们使用像 'four' 这样的多字符文字来处理这些情况,但编译器现在警告说 - 使用数组似乎是一个合适的替代品。
    【解决方案4】:

    您看到的是 C 和 C++ 之间的差异。 C 允许您有额外的初始化程序,这些初始化程序将被忽略。 C++ 禁止这样做——如果您为字符串(或数组)指定大小,它必须足够大以容纳所有初始化程序(包括 NUL 终止符,如果是字符串),或者代码格式不正确(“不允许 - 期望编译器拒绝它”的标准术语)。

    【讨论】:

    • 没有。我认为额外的 NUL 被视为一种特殊情况。如果你让它 char 四[4] = "fiveX";你在 C 中得到一个错误。
    • @EvilTeach - 我收到警告,而不是错误,"fiveX" 案例。
    • @EvilTeach(和 Carl):这(很大程度上)回到了标准的一个困难:他们需要对不正确的代码进行“诊断”(但如果选择的话,编译器仍然可以接受代码),但由编译器定义什么是(或不是)诊断。通常还需要特定的标志来实现一致性,因此默认情况下您可能得不到那么多。
    • 它似乎在我的平台上工作,没有任何特定的标志。你能举个例子吗,代码不起作用,或者除非设置了特定的标志,否则代码不起作用?
    • @EvilTeach:代码在没有特定标志的情况下无法运行,因为没有正确的标志,许多编译器将(例如)允许应该 确实被标记为错误。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-09
    • 1970-01-01
    • 1970-01-01
    • 2010-11-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多