【问题标题】:Inconsistent gcc diagnostic for string initialization字符串初始化的不一致 gcc 诊断
【发布时间】:2015-09-26 14:28:36
【问题描述】:

我正在使用 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";
}

我认为这两种形式是 100% 等效的。 C标准等中是否有任何理由或微妙之处,为什么后者不应该发出警告?

或者这是一个编译器错误?我知道与 C++ 不同,C 标准允许过多的初始化程序,所以正式地说,我不相信 gcc 是 需要 来进行诊断的。但我希望编译器能始终如一地发出警告。

【问题讨论】:

  • 这个问题类似于假设的重复,但我很好奇不一致警告的具体情况,假设重复的答案都没有解决。我相信我在这里也收到了一些更好的答案。重新开放。 (随意关闭另一个作为这个的副本,我不会干预它,因为我是部分的:))
  • "我知道 C 标准允许多余的初始化程序,不像 C++" -- 你这是什么意思?正如对重复问题的回答所说,C 明确允许对象的确切长度的字符串文字; C++ 没有。 C 通常不允许过多的初始化程序; int arr[2] = { 1, 2, 3, 4 }; 在两种语言中都是非法的。
  • 警告并不一致。 C 对字符串文字有一个特定的特殊情况规则;对于花括号初始化器,它没有这样的规则。在char b[5] = "hello"; 中,初始化程序没有为b[5] 提供值。
  • @KeithThompson 我相信这确实是 gcc 在这两种情况下表现不同的原因。 Ouah 引用了涵盖这两种情况的相关部分。

标签: c gcc initializer-list


【解决方案1】:

char b[5] = "hello";  

\0 未附加到字符串,因为数组 b 的大小为 5。这是有效的。编译器认为它是

char b[5] = {'h','e','l','l','o'};

这里bchars 的数组。但是,它不能用于假定字符串文字的地方。例如,您不能在 printf 中将 b%s 说明符或 str 系列函数一起使用。

【讨论】:

  • 确实如此。但是为什么它在这两种情况下没有一致地发出警告呢?
  • @Lundin;因为编译器知道如果初始值设定项是字符串字面量,那么 \0 可能附加也可能不附加取决于数组/缓冲区的大小。
  • 没有附加到字符串,因为数组 a 你的意思是数组 b,对吗?但这还不足以解释为什么char b[5] = "hello"; 有效而char b[5] = "hello!"; 无效。
【解决方案2】:

同时:

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

无效。

(C11, 6.7.9p2) “任何初始化器都不应尝试为未包含在正在初始化的实体中的对象提供值。”

这个:

char b[5] = "hello";

C 明确允许(强调我的):

(C11, 6.7.9p14) "一个字符类型的数组可以由一个字符串字面量或 UTF-8 字串字面量来初始化,可选用大括号括起来。字符串字面量的连续字节(包括终止的 null字符(如果有空间或如果数组大小未知)初始化数组的元素。”

但是

 char b[5] = "hello!";

无效。

【讨论】:

  • 在我看来,§1 和§14 相互矛盾,因为字符串文字仍然是初始化程序。 C 标准中的错误?
  • @Lundin 我不认为这是一个错误,而是当初始化程序是字符串文字时作为特殊规定。
【解决方案3】:

这是 C 标准中的一个奇怪的怪癖。过去,人们偶尔会使用固定长度、非空终止的字符串。 (一个例子是 V7 Unix 中的 14 个字符的文件名。)因此,为了让那些旧程序继续编译,使用字符串常量初始化显式大小的 char 数组是合法的,该字符串常量最终会刮掉 '\0' ,正如您刚刚观察到的那样。

我同意 {'h','e','l','l','o','\0'} 初始化程序发出警告而 "hello" 没有发出警告是令人惊讶的。但这是两种截然不同的形式,事实证明它们的规则是不同的。当您为数组指定大小并使用{} 表单时,必须为所有初始化程序留出空间。但是,当您给出尺寸并使用 "" 表单时,这种情况有一个特殊的例外,并且仅适用于那种情况。

(这两种形式在 C++ 中也是不合法的。)

【讨论】:

  • 尽管代码是有效的,但对char b[5] = "hello"; 发出警告将有助于大多数程序员避免愚蠢的错误。为避免警告,始终可以使用显式 char b[5] = { 'h', 'e', 'l', 'l', 'o' };
猜你喜欢
  • 2016-12-10
  • 1970-01-01
  • 1970-01-01
  • 2011-07-24
  • 1970-01-01
  • 2011-03-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多