簡體   English   中英

為什么gcc允許char數組初始化的字符串文字大於array?

[英]Why does gcc allow char array initialization with string literal larger than array?

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

C中的字符串文字在內部以nul字符終止。 因此,上述代碼應該給出編譯錯誤,因為字符串文字Network的實際長度為8,並且無法放入char[7]數組中。

但是,Ubuntu上的gcc (即使使用-Wall )也可以編譯此代碼,而不會出現任何錯誤或警告。 為什么gcc允許這樣做而不將其標記為編譯錯誤?

當char數組的大小小於字符串文字時,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的字符串文字初始化char數組在C中是可以的,但在C ++中是錯誤的。 這就解釋了gcc和VC ++在行為上的區別。

如果使用VC ++編譯與C文件相同的文件,則不會出錯。 如果使用g ++將其編譯為C ++文件,則會出現錯誤。

C標准說:

字符類型的數組可以由字符串文字或UTF-8字符串文字初始化,並可選地用大括號括起來。 字符串文字的連續字節(如果有空間或數組大小未知,則包括終止空字符)將初始化數組的元素。

[...]

實施例8

報關單

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

定義“普通”字符數組對象st其元素用字符串文字初始化。 此聲明與

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

C11標准草案的 6.7.9節,最終標准中的實際措詞可能有所不同。)

這意味着,如果數組沒有空間,則刪除終止符是完全正確的。 也許這是出乎意料的,但這恰恰是該語言應該如何工作以及(至少對我而言)一個眾所周知的功能。

相反,C ++標准說:

初始化器的數量不得超過數組元素的數量。

例:

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

格式錯誤,因為隱含的尾隨'\\ 0'沒有空格。

(C ++ 2011草案n3242的 8.5.2。)

在C和Unix的早期,內存和磁盤很小,因此實際上不使用NUL字節存儲在字符串的末尾。 如果字符串變量的長度為七個字符,則可以在其中存儲七個字符的字符串,並且由於最大長度為七個,因此即使沒有終止符,您也知道字符串在此處結束。 這就是為什么strncpy會按其方式工作。

盡管unwind的答案說明了為什么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警告此問題的唯一選項。 您可以編寫一個簡短的腳本,以快速從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

聲明字符串文字的首選方法通常是:

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

讓編譯器弄清楚。 手動指定數組大小並使它與字符串文字的實際長度保持同步非常麻煩...

因此,我想GCC除了警告以外,沒有其他事情。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM