2017-10-11 99 views
2

有一些簡單的代碼,其中clang和gcc的行爲有所不同。如何在clang中關閉本地數組合並?

int t; 
extern void abort (void); 

int f(int t, const int *a) 
{ 
const int b[] = { 1, 2, 3}; 
if (!t) 
    return f(1, b); 
return b == a; 
} 

int main(void) 
{ 
if (f(0, 0)) 
    abort(); 
return 0; 
} 

鏘:

> clang -v 
clang version 4.0.1 (tags/RELEASE_401/final) 
Target: x86_64-unknown-linux-gnu 
Thread model: posix 
> clang test.c 
> ./a.out 
Aborted 

GCC:

> gcc -v 
Target: x86_64-suse-linux 
Thread model: posix 
gcc version 7.2.0 (GCC) 
> gcc test.c 
> ./a.out 
> echo $? 
0 

原因是很明顯的:是實現定義的行爲和鏗鏘合併當地不變陣列全球性的。

但讓我說我想要一致的行爲。我可以在clang中打開或關閉某些開關,以禁用此優化,併爲不同的堆棧幀真誠地創建不同的本地數組(即使是常數)。

回答

3

您正在尋找的叮噹中的選項是-fno-merge-all-constants。如果你想達到相反的目的,你可以在gcc中用-fmerge-all-constants啓用它。但在GCC選項的文件讓我好奇:

語言如C或C++要求每個變量,包括遞歸調用同一個變量的多個實例,有不同的位置,因此使用非此選項結果符合行爲。

以某種方式可能暗示鐺唯一的位被允許與該逃脫是(C11,6.5.2.4):

  • 字符串文本,並帶有const限定類型的複合文字不需要指定不同的對象。
  • 這裏的問題是你的代碼沒有複合文字。

    其實也有關於這個鐺一個bug報告,看來,開發商都知道,這是不符合要求:https://bugs.llvm.org/show_bug.cgi?id=18538

    在那裏有趣的評論是:

    這是我能想到的唯一情況是(我的頭頂)clang故意不符合標準,並且有一個標誌使其符合標準。還有其他一些我們故意不符合的地方,因爲我們認爲標準是錯誤的(通常我們試圖在這些情況下修正標準)。

    +0

    複合文字的變量應該是'const int * b',我想。 –

    +0

    @JensGustedt是的,我知道,它不應該工作,但它在叮噹中。無論如何,我刪除了切向實驗,因爲考慮到這是來自叮噹的故意行爲,所以它是無關緊要的。 – Art

    +0

    謝謝,選項正是我所尋找的。 –

    3

    但看來clang被重用爲在f()本地範圍變量b在同一個陣列,但不能的實現定義的基礎上是合理的。實現定義的行爲在標準中明確地標出,並且符合的實現記錄了實現定義行爲的每個區域的實際行爲。這不是標準授予這種緯度的區域。

    相反,clang生成的程序的行爲是不符合的,而且Clang不符合生成此類代碼的規定。該標準特別說

    對於[具有自動存儲持續時間的對象]不具有可變長度數組類型, 其壽命從進入與它相關聯的 直到該塊的執行塊延伸以任何方式結束。如果遞歸輸入的塊(輸入一個 封閉塊或調用函數掛起,但並沒有結束, 執行當前塊的。), 對象的新實例被創建每次

    C2011, 6.2.4/6;強調)

    在問題在這種情況下的對象確實具有自動存儲持續時間和不具有可變長度數組類型,所以標準規定,它們是不同的對象。它們是具有const -qualifed元素類型的數組,不允許clang重用該數組。

    但讓我說我想要一致的行爲。我可以在clang中打開或關閉某些開關,以禁用此優化,併爲不同的堆棧幀真誠地創建不同的本地數組(即使是常數)。

    您可以且應該報告針對叮噹的錯誤,除非已經報告此問題。修復該錯誤的時間可能比您想要等待的時間更長,但我沒有找到任何可以調整此行爲的命令行標誌的文檔。

    另一個答案表明,實際上有一個選項控制這種行爲。我完全準備相信,因爲我以前發現Clang的文檔在其他方面不完整,但不應該有必要明確地將關閉這樣的選項以實現語言一致性。