gcc对字符串初始化的诊断不一致

8
我使用的是gcc 4.9.1/Mingw,并使用以下命令编译代码:

gcc test.c -otest.exe -std=c11 -pedantic-errors -Wall -Wextra

这段代码会产生诊断信息:
int main (void)
{
  char a[5] = {'h','e','l','l','o','\0'};
}

错误:字符数组初始化器中存在过多元素 char a[5]

然而,这段代码不会产生警告:

int main (void)
{
  char b[5] = "hello";
}

我认为这两种形式是完全等价的。C标准中是否有任何理由或细微差别,使得后者不应该发出警告?
还是这是编译器的一个bug? 我知道C标准允许超出初始化器的数量,不像C ++,所以从形式上来说,我不认为gcc需要提供诊断。但是我希望编译器能够始终给出警告。

这个问题与所谓的重复问题相似,但我对不一致警告的特定情况很好奇,而且所谓的重复问题的答案都没有解决这个问题。我相信我在这里也得到了一些更好的答案。重新开放。(如果您愿意,可以将另一个问题关闭为此问题的重复,我不会干涉它,因为我有偏见 :)) - Lundin
1
我知道 C 标准允许多余的初始化项,而 C++ 则不然” -- 这是什么意思?正如回答重复问题所说,C 明确允许使用恰好等于对象长度的字符串字面量;但 C++ 不允许。一般情况下,C 不允许超出初始化项的数量;例如 int arr[2] = { 1, 2, 3, 4 }; 在两种语言中都是不合法的。 - Keith Thompson
2
警告并不矛盾。C语言对于字符串字面量有一个特殊的规则,但是对于花括号初始化器却没有这样的规则。在char b[5] = "hello";中,初始化器并没有为b[5]提供值。 - Keith Thompson
@KeithThompson 我相信这正是gcc为什么对这两种情况表现不同的原因。Ouah已经引用了涵盖这两种情况的相关部分。 - Lundin
3个回答

15

当:

 char a[5] = {'h','e','l','l','o','\0'};

无效。

(C11,6.7.9p2)“初始化程序不能尝试为未包含在正在初始化的实体中的对象提供值。”

这个:

char b[5] = "hello";
(C11, 6.7.9p14)指出: "字符类型的数组可以通过字符字面值或UTF-8字符串字面值进行初始化,可以选择用大括号括起来。 字符串字面值的连续字节(包括如果有足够空间的话终止的空字符或者该数组大小未知)将初始化数组的元素。" 但是,
 char b[5] = "hello!";

无效。


那么在我看来,§1和§14互相矛盾,因为字符串字面值仍然是一个初始化器。这是C标准中的一个错误吗? - Lundin
2
@Lundin 我不认为这是一个错误,而是当初始化程序是字符串字面值时的特殊规定。 - ouah

10
这是C标准中的一个奇怪的习惯。早些年,人们偶尔会使用固定长度的非空终止字符串(例如V7 Unix中的14个字符文件名)。为了让那些旧程序继续编译,可以使用字符串常量初始化一个明确大小的char数组,并刮掉\0,就像你刚刚观察到的那样。
我同意,{'h', 'e', 'l', 'l', 'o', '\0'}这个初始值设定在警告而"hello"没有警告,这是令人惊讶的。但这两种形式是非常不同的,事实证明它们的规则也是不同的。当你给你的数组一个大小并使用{}形式时,必须有足够的空间来容纳所有的初始化项。但当你给出一个大小并使用""形式时,只有这种情况下才有一个特殊的例外。
(在C++中,这两种形式都是不合法的。)

1
尽管代码是有效的,但对于char b[5] = "hello";发出警告可以帮助大多数程序员避免愚蠢的错误。为了避免警告,始终可以使用显式的char b[5] = { 'h', 'e', 'l', 'l', 'o' }; - chqrlie

3

In

char b[5] = "hello";  
\0没有被添加到字符串中,因为数组b的大小为5。这是有效的。编译器将其视为。
char b[5] = {'h','e','l','l','o'};

这里b是一个char类型的数组。但是,它不能被用在需要使用字符串字面值的地方。例如,你不能在使用%s格式说明符的printf函数或者str系列函数中使用b


确实。但为什么它在这两种情况之间不能始终发出警告呢? - Lundin
@Lundin; 因为编译器知道,如果初始化程序是字符串文字,则\0可能附加或不附加取决于数组/缓冲区的大小。 - haccks
1
дҪ зҡ„ж„ҸжҖқжҳҜж•°з»„bпјҢеҜ№еҗ—пјҹдҪҶиҝҷиҝҳдёҚи¶ід»Ҙи§ЈйҮҠдёәд»Җд№Ҳchar b[5] = "hello";жҳҜжңүж•Ҳзҡ„пјҢиҖҢchar b[5] = "hello!";еҲҷж— ж•ҲгҖӮ - ouah

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接