为什么海湾合作委员会允许使用字符串字面量超过数组大字符数组初始化?(Why does gcc all

2019-07-04 01:02发布

int main()
{
    char a[7] = "Network";
    return 0;
}

用C 字符串文字NUL字符内部终止。 所以,上面的代码应该给编译错误,因为字符串文字的实际长度Network是8,它不能适合在一个char[7]数组。

然而, 海湾合作委员会 (即使-Wall )在Ubuntu上编译没有任何错误或警告的代码。 为什么GCC允许这个,而不是其标记为编译错误?

GCC只给出一个警告(仍然没有错误!)当字符数组大小比字符串字面量较小。 例如,它警告上:

char a[6] = "Network";

【相关的Visual C ++ 2012给出了一个编译错误char a[7]

1>d:\main.cpp(3): error C2117: 'a' : array bounds overflow
1> d:\main.cpp(3) : see declaration of 'a'

Answer 1:

初始化与文字的字符串为大于它在C细,但错误在C ++字符数组。 这也解释了在gcc和VC ++之间的行为差​​异。

如果您编译一样用VC ++ C文件,你会得到任何错误。 如果你编译它与G ++一个C ++文件,你会得到一个错误。

C标准说:

字符类型的阵列可以由一个字符串文字或UTF-8字符串文字进行初始化,任选在大括号。 字符串文字的连续字节(包括终止空字符,如果有房间或如果阵列是未知大小的)初始化所述阵列的所述元件。

[...]

例8

声明

 char s[] = "abc", t[3] = "abc"; 

定义“”普通“” char数组对象st ,其元素与字符串文字被初始化。 该声明是相同的

 char s[] = { 'a', 'b', 'c', '\0' }, t[] = { 'a', 'b', 'c' }; 

(在第6.7.9 C11标准草案 ,在最终标准实际措辞可能会有所不同。)

这意味着,这是完全正确的放弃终止字符,如果数组没有余地了。 这也许出乎意料,但它的语言究竟如何工作的,以及(至少对我来说)的著名特色。

与此相反,在C ++标准说:

不应当有更多的初始化值多于数组元素。

例:

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

是形成不良的,因为存在用于暗示尾随“\ 0”没有空间。

(8.5.2 C ++ 2011草案n3242 。)



Answer 2:

声明字符串文本的方式参访通常为:

   char a[] = "Network";
   printf("size of a: %d\n", sizeof a); // The compiler 'knows' the size of a.
   // this prints '8'

让编译器看着办吧。 这是繁琐的手动指定数组的大小,并把它与字符串常量的实际长度同步...

所以我想GCC并没有真正有什么比一个警告的麻烦。



Answer 3:

在C和Unix的初期,内存和磁盘太小,所以不存储在所述字符串的末尾的字节NUL实际上,使用的是一种技术。 如果字符串变量是7个字符长,你可以一七字符串存储在里面,因为7是最大长度,你明明知道这个字符串结束那里,即使没有终止符。 这就是为什么strncpy()函数的工作方式是这样。



Answer 4:

虽然开卷的回答解释了为什么gcc不警告这一点,它没有说你可以做些什么。

gcc-Wc++-compat警告选项检测与信息这一具体问题:

foo.c: In function ‘main’:
foo.c:3:17: warning: initializer-string for array chars is too long for C++ [-Wc++-compat]

这将导致唯一的选择gcc警告这个问题。 你可以写一个简短的脚本来快速的grep警告选项出的gcc的手册页,尝试用每个编译,并看它是否抱怨。

$ time for F in $(man gcc | grep -o -- '-W[^= ]*')
    do if gcc -c "${F}" foo.c |& grep :3 >& /dev/null; then
         echo "${F}"; gcc -c "${F}" foo.c
    fi
  done
man gcc | grep -o -- '-W[^= ]*')
man gcc | grep -o -- '-W[^= ]*'
-Wall
foo.c: In function ‘main’:
foo.c:3:10: warning: unused variable ‘a’ [-Wunused-variable]
-Wc++-compat
foo.c: In function ‘main’:
foo.c:3:17: warning: initializer-string for array chars is too long for C++ [-Wc++-compat]
-Wunused
foo.c: In function ‘main’:
foo.c:3:10: warning: unused variable ‘a’ [-Wunused-variable]
-Wunused-variable
foo.c: In function ‘main’:
foo.c:3:10: warning: unused variable ‘a’ [-Wunused-variable]
-Wtraditional
foo.c: In function ‘main’:
foo.c:3:5: warning: traditional C rejects automatic aggregate initialization [-Wtraditional]
-Wall
foo.c: In function ‘main’:
foo.c:3:10: warning: unused variable ‘a’ [-Wunused-variable]
-Wall
foo.c: In function ‘main’:
foo.c:3:10: warning: unused variable ‘a’ [-Wunused-variable]
-Wunused-variable
foo.c: In function ‘main’:
foo.c:3:10: warning: unused variable ‘a’ [-Wunused-variable]
-Wunused
foo.c: In function ‘main’:
foo.c:3:10: warning: unused variable ‘a’ [-Wunused-variable]
-Wunused
foo.c: In function ‘main’:
foo.c:3:10: warning: unused variable ‘a’ [-Wunused-variable]
-Wall
foo.c: In function ‘main’:
foo.c:3:10: warning: unused variable ‘a’ [-Wunused-variable]
-Wall
foo.c: In function ‘main’:
foo.c:3:10: warning: unused variable ‘a’ [-Wunused-variable]
-Wall
foo.c: In function ‘main’:
foo.c:3:10: warning: unused variable ‘a’ [-Wunused-variable]
-Wunused
foo.c: In function ‘main’:
foo.c:3:10: warning: unused variable ‘a’ [-Wunused-variable]
-Wunused-variable
foo.c: In function ‘main’:
foo.c:3:10: warning: unused variable ‘a’ [-Wunused-variable]
-Wunused
foo.c: In function ‘main’:
foo.c:3:10: warning: unused variable ‘a’ [-Wunused-variable]
-Wunused
foo.c: In function ‘main’:
foo.c:3:10: warning: unused variable ‘a’ [-Wunused-variable]
-Wunused
foo.c: In function ‘main’:
foo.c:3:10: warning: unused variable ‘a’ [-Wunused-variable]
-Wall
foo.c: In function ‘main’:
foo.c:3:10: warning: unused variable ‘a’ [-Wunused-variable]
-Wall
foo.c: In function ‘main’:
foo.c:3:10: warning: unused variable ‘a’ [-Wunused-variable]
-Wall
foo.c: In function ‘main’:
foo.c:3:10: warning: unused variable ‘a’ [-Wunused-variable]
-Wall
foo.c: In function ‘main’:
foo.c:3:10: warning: unused variable ‘a’ [-Wunused-variable]
-Wtraditional
foo.c: In function ‘main’:
foo.c:3:5: warning: traditional C rejects automatic aggregate initialization [-Wtraditional]
-Wtraditional
foo.c: In function ‘main’:
foo.c:3:5: warning: traditional C rejects automatic aggregate initialization [-Wtraditional]
-Wc++-compat
foo.c: In function ‘main’:
foo.c:3:17: warning: initializer-string for array chars is too long for C++ [-Wc++-compat]
-Wall
foo.c: In function ‘main’:
foo.c:3:10: warning: unused variable ‘a’ [-Wunused-variable]
-Wtraditional
foo.c: In function ‘main’:
foo.c:3:5: warning: traditional C rejects automatic aggregate initialization [-Wtraditional]
-Wall
foo.c: In function ‘main’:
foo.c:3:10: warning: unused variable ‘a’ [-Wunused-variable]
-Wall
foo.c: In function ‘main’:
foo.c:3:10: warning: unused variable ‘a’ [-Wunused-variable]
-Wall
foo.c: In function ‘main’:
foo.c:3:10: warning: unused variable ‘a’ [-Wunused-variable]
-Wall
foo.c: In function ‘main’:
foo.c:3:10: warning: unused variable ‘a’ [-Wunused-variable]
-Wall
foo.c: In function ‘main’:
foo.c:3:10: warning: unused variable ‘a’ [-Wunused-variable]
-Wtraditional
foo.c: In function ‘main’:
foo.c:3:5: warning: traditional C rejects automatic aggregate initialization [-Wtraditional]

real    0m26.399s
user    0m5.128s
sys 0m15.329s

一般来说, 棉绒般的工具,如splint会警告你的各种潜在问题。 在这种情况下,它会说:

foo.c:3:17: String literal with 8 characters is assigned to char [7] (no room
               for null terminator): "Network"
  A string literal is assigned to a char array that is not big enough to hold
  the null terminator. (Use -stringliteralnoroom to inhibit warning)
foo.c:3:10: Variable a declared but not used


文章来源: Why does gcc allow char array initialization with string literal larger than array?