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'
初始化与文字的字符串为大于它在C细,但错误在C ++字符数组。 这也解释了在gcc和VC ++之间的行为差异。
如果您编译一样用VC ++ C文件,你会得到任何错误。 如果你编译它与G ++一个C ++文件,你会得到一个错误。
C标准说:
字符类型的阵列可以由一个字符串文字或UTF-8字符串文字进行初始化,任选在大括号。 字符串文字的连续字节(包括终止空字符,如果有房间或如果阵列是未知大小的)初始化所述阵列的所述元件。
[...]
例8
声明
char s[] = "abc", t[3] = "abc";
定义“”普通“” char数组对象s
和t
,其元素与字符串文字被初始化。 该声明是相同的
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 。)
声明字符串文本的方式参访通常为:
char a[] = "Network";
printf("size of a: %d\n", sizeof a); // The compiler 'knows' the size of a.
// this prints '8'
让编译器看着办吧。 这是繁琐的手动指定数组的大小,并把它与字符串常量的实际长度同步...
所以我想GCC并没有真正有什么比一个警告的麻烦。
在C和Unix的初期,内存和磁盘太小,所以不存储在所述字符串的末尾的字节NUL实际上,使用的是一种技术。 如果字符串变量是7个字符长,你可以一七字符串存储在里面,因为7是最大长度,你明明知道这个字符串结束那里,即使没有终止符。 这就是为什么strncpy()函数的工作方式是这样。
虽然开卷的回答解释了为什么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?