为什么编译器没有检测到字符串常量初始化中的越界?

Pal*_*Dot 8 c arrays compilation

我在一本书中读到了这个问题及其答案.但我不明白这本书的理由.

下面的代码会编译吗?

int main()
{
   char str[5] = "fast enough";
   return 0;
}
Run Code Online (Sandbox Code Playgroud)

答案是:

是的.如果超出数组的边界,编译器永远不会检测到错误.

我无法得到它.

有人可以解释一下吗?

Mic*_*urr 6

在C++标准中,8.5.2/2字符数组表示:

没有比数组元素更多的初始化器.

在C99标准中,6.7.8/2初始化说:

初始化程序不应尝试为未初始化的实体中包含的对象提供值

C90 6.5.7初始化器说类似.

但请注意,对于C(C90和C99),如果有空间,'\ 0'终止字符将被放入数组中.如果终止符不适合,则不是错误(C99 6.7.8/14:"字符串文字的连续字符(如果有空间或数组大小未知,则包括终止空字符)初始化元素阵列").

另一方面,C++标准有一个例子,表明如果终止字符没有空间,应该诊断错误.

在任何一种情况下,这应该被诊断为所有编译器中的错误:

char str[5] = "fast enough";
Run Code Online (Sandbox Code Playgroud)

也许前ANSI编译器不是那么严格,但任何合理的现代编译器都应该诊断出来.

  • GCC 3.4.5(编译为 C)仅给出警告(我认为它应该将其诊断为错误)。GCC 编译为 C++、MSVC 8、Digital Mars 8.5 和 Comeau 4.3.10.1 都会产生错误。 (2认同)

Mar*_*off 5

你的书必须很旧,因为即使没有-Wall开启,gcc也会发出警告:

$ gcc c.c
c.c: In function `main':
c.c:6: warning: initializer-string for array of chars is too long

如果我们稍微更新程序:

#include <stdio.h>

int main(int argc, char **argv)
{

        char str[5] = "1234567890";
        printf("%s\n", str);
        return 0;
}
Run Code Online (Sandbox Code Playgroud)

我们可以看到gcc似乎将字符串截断为你指定的长度; 我假设恰好是一个'\0'在那里str[6]会是这样,因为否则我们应该在5后看到垃圾; 但也许gcc隐含地制作str一个长度为6的数组并自动将其固定'\0'在那里 - 我不确定.

$ gcc c.c && ./a.exe
c.c: In function `main':
c.c:6: warning: initializer-string for array of chars is too long
12345

  • 是的,它确实; 这表明一些编译器*会*检测到常量字符串太长,并且它们会截断字符串. (4认同)