2013-06-26 77 views
2

ķ& RC(第二版,第5.5節)規定如下(由我強調):這是否應該生成gcc警告?

char amessage[] = "a message"; /* an array */ 
char *pmessage = amessage; /* a pointer */ 

amessage是一個數組只是大足以容納的字符序列和 '\ 0'初始化它。陣列中的單個字符可能會更改,但是amessage將始終指代相同的存儲。 OTOH,pmessage是一個指針,初始化爲指向一個字符串常量;該指針可能隨後被修改以指向其他地方;但結果是undefined如果您嘗試修改字符串內容

現在,我的問題是,是否應的gcc 4.6.1(或C99)在我的Linux系統中產生,而編譯下面的程序與-Wall警告:

int main(void) { 
    char amessage[] = "a message"; 
    char *pmessage = "a message"; 
    pmessage[0] = 'b'; 
    return 0; 
} 

(我發現,GCC不會產生如果我正確解釋上述內容,我的期望是它應該)

+0

即使我這樣做,結果也是一樣的:char * pmessage =「a message」; –

+3

我沒有在我面前的K&R,但你確定你引用的代碼是否正確?我認爲它是'char * pmessage =「消息」;在這種情況下,行爲是未定義的,因爲'pmessage'指向一個字符串字面值,而不是你創建的數組。 –

+0

@KedarMhaswade原來,代碼是正確的,因此與您描述的錯誤不匹配。是不是''char * p =「foo」;'instead? – 2013-06-26 00:49:37

回答

2

僅僅因爲代碼錯誤並不意味着gcc可以爲它生成警告。如果在編譯時可以檢測到所有未定義行爲的實例,那麼沒有理由使行爲未定義。它可能只是一個強制性的錯誤,或者編譯成相當於abort();或類似的錯誤。

我同意gcc很容易在這種情況下生成警告。但是如何:

int main(void) { 
    char amessage[] = "a message"; 
    char *pmessage = "a message"; 
    if (is_prime(some_constant_with_100_million_digits)) 
     pmessage = amessage; 
    pmessage[0] = 'b'; 
    return 0; 
} 

它是否調用UB?

5

雖然您從K & R的引用是正確的,但我不希望這段代碼產生警告,因爲這樣的錯誤在一般情況下很難跟蹤。

例如,假設一段代碼在您的指針最初指向修改的內存塊,那麼你操縱它一點點,然後分配給它指向一個字符串:

char [] ok = "quick brown fox"; 
char *ptr = ok; 
for (int i = 0 ; i != 5 ; i++) { 
    *ptr++ = '-'; // OK 
} 
ptr = "jumps over the lazy dog"; 
ptr[0] = 'J'; // Bad 

對於一個編譯器,跟蹤這些分配併發出警告將是非常棘手的。覆蓋所有情況將是不可能的,因爲指向字符串文字的指針可能來自外部鏈接的函數。

+0

謝謝!這有幫助,但對於gcc als來說很難o很難像皮棉一樣的程序?我在C程序上運行了_splint_並生成以下代碼: array-pointer-chars.c:5:3:可疑修改觀察者pmessage [0]: pmessage [0] ='b' 用觀察者可能會被修改。觀察者存儲可能不會被修改。 (使用-modobserver來禁止警告) –

+0

@KedarMhaswade'splint'和'lint'是靜態代碼分析的好工具。你也可以在'valgrind'中運行你的程序來動態分析你的程序執行的內存訪問。 – dasblinkenlight

+0

謝謝,@dasblinkenlight。我應該更好地理解編譯器期望什麼,以及應該留給靜態代碼分析器。順便說一下,valgrind報告'進程終止與信號11(SIGSEGV)的默認行動'在我的程序的可執行文件。我應該花更多時間瞭解valgrind ... –

0

它可能不會警告,因爲它是未定義的。

同樣地,我可以這樣做:

char amessage[] = "a message"; 
char *pmessage = amessage; 
free(pmessage); 

而且它不會發出警告,但應該出現段錯誤。

我認爲警告是爲了定義的行爲。

+0

調用'free'是UB的完全不同的來源... –

0

嗯,它不應該說什麼,因爲pmessage不是一個指向const的指針,我猜它沒有提及它在這種情況下,或者是因爲它沒有做足夠的靜態分析(你可能會嘗試-O切換,看看是否會帶來更多洞察力),還是因爲在這種情況下沒有人說出任何內容 - 這通常意味着沒有機會從未定義的行爲中做出不直觀的優化。

GCC支持-Wwrite-strings這會在初始化時引發問題,迫使您將pmessage指向const,隨後使以下行成爲非法。