2011-06-13 60 views
32

在C++ IS的C.1.3(2003也是在C++ 11 IS中),該標準指出了ISO C和C++之間的區別;即,在Csizeof採用兩個參數

char arr[100]; 

sizeof(0, arr)返回sizeof(char*)在C,但100 ++。

我找不到sizeof兩個參數的文檔。明顯的後退是逗號運算符,但我不這麼認爲:C中的sizeof(arr)100; sizeof(0, arr)sizeof(char*)。在C++中,sizeof(0, arr)sizeof(arr)都是100

我可能會錯過本文中IS的全部觀點。誰能幫忙?這與在09年討論的問題類似,但沒有人提到IS,我認爲沒有給出正確的答案。


編輯:其實,IS在談論逗號操作符。因此,出於某種原因,(0, arr)在C中返回char*,但在C++中返回char[100]。爲什麼?

+0

實際上,IS *是在談論逗號運算符,但我仍然不明白髮生了什麼。 – John 2011-06-13 14:13:14

+3

有趣。我從來沒有見過2個參數的「sizeof」。它被定義爲一個一元運算符,並且可選地使用'()',這會排除多個參數。 – 2011-06-13 14:16:43

+1

@PeterRowell:沒錯。這裏傳遞給'sizeof'的表達式使用逗號運算符。即'sizeof x',其中'x'是表達式'(0,arr)'。 – 2011-06-13 14:19:01

回答

23

在C中,由於逗號運算符與rvalues和lvalues相關的不同規範(不是唯一可以找到這種差異的地方),因此數組正在衰減爲指針。在C++中,數組保留一個數組,產生正確的結果。

5

這不是sizeof帶兩個參數。 sizeof是一個操作符,而不是一個函數。

考慮一下,(0, arr)是一個使用逗號運算符的表達式,其他所有內容都落實到位。

+0

這個問題說:「顯而易見的後備是逗號運算符,但我不這麼認爲」,並且你有4個贊成「考慮......逗號運算符,其他所有東西都落到位」? – 2011-06-13 18:03:07

+0

@邁克爾:至少,我說的是OP認爲是錯的。 – 2011-06-13 19:14:10

+0

+1提到'sizeof'是一個運算符。它需要一個表達式或一個表達式。 – 2011-06-27 10:08:12

42

在C中,逗號操作符不產生左值,因此該陣列arr這是一個左值衰變成指針類型,是一個右值(在這種情況下)。所以sizeof(0,arr)等於sizeof(char*),由於左值到右值的轉換。

但在C++中,逗號運算符產生一個左值。沒有左值對右值的轉換。因此sizeof(0,arr)保持不變,相當於sizeof(char[100])

順便說一下,sizeof不是一個函數,它是一個運算符。所以,以下是完全合法的C++(和C,如果你想像的printf代替cout):

int a[100], b[200], c[300], d[400]; 
cout << sizeof(a,b,c,d) << endl; 

演示:http://www.ideone.com/CtEhn

你可能會認爲我已經通過了4個操作數sizeof但這是錯誤的。 sizeof運行於結果的逗號運算符。由於許多逗號操作符,您會看到許多操作數。

4個操作數< => 3個逗號操作符;就像在1+2+3+4中一樣,有3個操作員,4個操作數。

以上是等同於以下(C++ 0x中有效):

auto & result = (a,b,c,d); //first all comma operators operate on the operands. 
cout << sizeof (result) << endl; //sizeof operates on the result 

演示:http://www.ideone.com/07VNf

所以其逗號操作,使你感到有很多論據。這裏逗號是一個運算符,但在函數調用中,逗號不是一個運算符,它的簡單參數分隔符。

function(a,b,c,d); //here comma acts a separator, not operator. 

所以sizeof(a,b,c,d)運行在,運營商的結果類型,正是以同樣的方式,sizeof(1+2+3+4)+運營商的結果類型進行操作。

另外請注意,您不能sizeof(int, char, short),正是因爲逗號運營商不能在類型操作。它僅在的值上運行。我認爲,sizeof是C和C++中唯一的運算符,它可以在類型上運行。在C++中,還有一個運算符可以在類型上運行。它的名字是typeid

+0

@Tomalak:謝謝。我用更多的解釋更新了它。 – Nawaz 2011-06-13 15:02:10

+4

關於最後一段:C++中的new操作符也可以在類型上操作。 – 2011-06-13 22:30:45

+1

@Nawaz:優秀的回答爵士! – Destructor 2015-10-04 14:11:44

6

它是一個逗號運算符。而你所說的差異與sizeof完全沒有關係。它們的區別在於C和C++語言之間的左值對右值,數組對指針和類似的衰減行爲。

C語言是相當好戰的在這方面:數組衰變爲指針幾乎立即(極少數特定情況下的例外),這就是爲什麼0, arr表達式的結果具有char *類型。它相當於0, (char *) arr

在C++語言中,數組保持「數組性」的時間更長。當在,的上下文中使用時,運算符數組不會衰減到指針(並且左值不會衰減到右值),這就是爲什麼在C++中0, arr表達式的類型仍然是char[100]

這就是解釋該示例中sizeof行爲的差異的原因。 ?:運算符是運算符的另一個示例,演示了衰減行爲中的類似差異,即sizeof(0 ? arr : arr)將在C和C++中給出不同的結果。基本上,這一切都源於C操作員通常不保留操作數的左值。很多操作員可以用來證明這種行爲。

+0

+1不是說這種行爲是因爲','會產生一個非左值,並且正確地說這是因爲C的觸發器幸福。並且不是說左值到右值的轉換將負責這個。 – 2011-06-13 19:22:06

3

sizeof不帶兩個參數。但它不是一個函數, 因此(...)不分隔函數參數,它們只是語法的一個可選部分,並強制分組。當您編寫 sizeof(0, arr)時,sizeof的參數是單個表達式0, arr。包含逗號運算符的單個表達式評估逗號左側的 表達式,並拋出其值(但不包括其 副作用),然後評估表達式在逗號 的右側,並將其值作爲完整表達式的值。

我不確定C,但這可能是 的差異。在C++中,除非需要 ,否則不會發生數組到指針的轉換;在C中,如果我沒有記錯,標準說它總是在除了某些情況下發生的地方。包括作爲sizeof的 運營商。在這種情況下,由於逗號運算符 對其操作數的類型沒有約束,所以在C++中不會發生數組到指針的轉換。在C中,逗號運算符的操作數 未在例外中列出,因此 數組到指針的轉換確實發生。 (在這種情況下,數組 是逗號運算符的操作數,而不是sizeof

1

正如幾位已經說了,我想補充的只有一件事,sizeof會操作員採取任何表達式或演員表演。 因爲這個原因,我習慣於把懷疑寫成大小隻有只有如果它是一個演員表達。

char *arr; 
struct xxx { ... } v; 

我會寫

sizeof arr 
sizeof v 

sizeof (struct xxx)  /* Note the space after the sizeof, it's important */ 
sizeof (char *) 

我做同樣的return沒有括號,因爲它不是一個函數調用,如果我把括號這是因爲表達式需要它們。

2

查看可能發生的最好方法是查看標準中的語法。如果我們看一下C99標準草案6.5.3元運算符款我們可以看到了sizeof的語法是:

sizeof unary-expression 
sizeof (type-name) 

所以第二個不適用,但如何在sizeof unary-expression在這個應用案件?如果我們從標準草案看部分A.2.1表達式並通過語法像這樣的工作:

unary-expression -> postfix-expression -> primary-expression -> (expression) 

我們避開了表達的parenthesizes,現在我們只需要看看文法逗號操作從部分6.5.17逗號操作,我們看到:

expression: 
    assignment-expression 
    expression , assignment-expression 

所以我們現在有:

sizeof(expression , assignment-expression) 
       ^
        | 
        comma operator 

表達賦值表達式可以帶我們到它具有以下語法基本表達式

primary-expression: 
    identifier 
    constant 
    string-literal 
    (expression) 

0恆定arr標識符所以我們有:

sizeof(constant , identifier) 

那麼逗號運算符在這裏做什麼?部6.5.17段落說:

逗號操作者的左操作數被評價爲空隙表達;評估後有一個 序列點。然後評估右操作數;結果有它的類型和價值。 97)

由於逗號操作者不是其中陣列不轉換爲它產生一個指針一個例外這是覆蓋在部分6.3.2.1左值,數組和功能指示器指針(),這意味着我們結束了:

sizeof(char *) 

C++語法是非常相似的,所以我們最終在同一個地方,但逗號運營商的工作方式不同。 C++標準牽伸部5.18逗號運算符說:

[...]的結果的類型和值是類型和右操作數的值;結果是相同的值類別作爲其右操作數的[...]

所以和陣列到指針沒有不需要轉換等等我們最終:

sizeof(char[100])