2015-05-31 63 views
25

下面的程序打印相同數量的兩倍上的gcc 4.8.2:確定數組大小時,括號是否有所作爲?

#include <stdio.h> 

int main() 
{ 
    char a[13]; 
    printf("sizeof a is %zu\n", sizeof a); 
    printf("sizeof(a) is %zu\n", sizeof(a)); 
} 

根據this reddit post,GCC是在這方面不符合標準的,因爲括號內的表達式是不例外的,用於當在列表上陣列到指針的衰減不會發生。

這傢伙是否正確?下面是相關標準報價:

除了當它是sizeof操作者或一元&操作者的操作數,或是用於初始化字符類型的陣列的字符串文字,或者是一個寬字符串文字用於初始化與wchar_t兼容的元素類型的數組,具有類型'數組類型'的左值轉換爲具有指向數組對象的初始成員並且不是左值的類型爲'指向類型的指針'的表達式。

只是要清楚,他認爲,(a)應該觸發數組到指針的衰減,因爲括號不能在上面(sizeof符,一元&操作,字符串文字作爲初始化)名單所涉及。

+7

不,這傢伙是嚴重困惑 –

+1

用他自己的話說,我會同意*最終困惑* – chqrlie

+1

我已經處理了這個東西大約15年,但我肯定回憶一個場景,我認爲,sizeof是否存在括號,這取決於指針的大小或元素的大小等。 –

回答

24

看起來多餘的括號會影響程序的語義,這是C標準中一個長期存在的問題,仍然沒有得到充分解決。

通常聲稱,((void*)0)在技術上不是空指針常量,因爲沒有規則說明括號內的空指針常量是空指針常量。

某些編譯器爲char s[] = ("abc");發出錯誤,因爲雖然可以從字符串文字初始化字符數組,但該規則不包括括起來的字符串文字。

有很多相似的例子。你找到了其中之一。

從我所知道的來看,共識基本上是規則應該是是C++所做的,但C從未正式採用過。C++使括號表達式在功能上等同於非括號表達式,並帶有一些明確規定的例外。這將一次覆蓋所有這些問題。

從技術上講,這個傢伙可能被認爲是正確的,但它對於沒有人真正遵循的標準的解釋過於嚴格,因爲這裏的標準很簡單,這是常識。

+1

一個人不能簡單地測試一個標識符是指向一個指針還是一個數組,這使得'sizeof(argv)'容易出錯是非常糟糕的。如果'sizeof(argv)'和'sizeof argv'被評估爲不同的事情會更糟糕。真正需要的是一個'(a)'操作符的計數,它計算一個數組元素的數量,並在應用於非數組時發出編譯時錯誤。 – chqrlie

+0

@chqrlie我寧願有構建塊需要創建'countof'(我通常看到它名爲'LENGTHOF',但要麼工作)我們自己。有了C11的'_Generic',我想所有的東西都像C++ 11的'decltype'一樣。如果我們有這個,我們可以靜態驗證'argv'的類型與'&* argv'不同。 – hvd

+0

我發現'LENGTHOF(a)'因爲字符串的長度和相應的字節數組的大小之間可能存在混淆而沒有吸引力。我同意這些工具就足夠了,比如:typeof(a)!= typeof(&*(a))' – chqrlie

21

從C99,6.5.1,在括號表達式:

它的類型和值的那些相同的加括號的表達。

乍一看,似乎這與你指的是(6.3.2.1)例外列表中的衝突:

除了當它是sizeof運營商或一元的操作數&操作者,或是用於初始化一個數組,其具有輸入「類型的陣列」被轉換爲與類型「指針輸入」的表達的表達一個字符串文字...

然而,該列表在運算符/操作數的上下文中;括號似乎不被視爲運營商(基於6.5節結構所隱含的分類)。

+0

您可以直接鏈接到該部分,感謝一些勇敢的靈魂花了很多時間將PDF文檔轉換爲html:http://www.iso-9899.info/n1256.html#6.5.1p5,http:// www。 iso-9899.info/n1256.html#6.3.2.1p3 ...或對於C11:http://www.iso-9899.info/n1570.html#6.5.1p5,http://www.iso-9899 .info/n1570.html#6.3.2.1p3 – Sebivor

+1

C11似乎只允許在父級版本(6.5.3#1)中使用_type-name_。關於這一點,圍繞_unary-expression_括號的版本將在語法上成爲未包含的版本,括號是_unary-expression_的一部分。使編譯器的工作變得不容易。編輯:相同的C99。 – Olaf