sizeof有两个论点

时间:2011-06-13 14:11:45

标签: c++ c arrays pointers comma-operator

在C ++ IS的C.1.3中(2003年。它也在C ++ 11 IS中),该标准指出了ISO C和C ++之间的差异;即,

char arr[100];

sizeof(0, arr)在C中返回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]。为什么呢?

7 个答案:

答案 0 :(得分:46)

在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

答案 1 :(得分:23)

在C中,然后数组衰减为指针,因为逗号运算符与rvalues和lvalues的关系不同(不是唯一可以找到这种差异的地方)。在C ++中,数组保持一个数组,产生正确的结果。

答案 2 :(得分:6)

这是一个逗号运算符。你所谈论的差异与sizeof完全无关。区别在于左值到右值,数组到指针以及C和C ++语言之间类似的衰减行为。

在这方面,C语言相当触发快乐:数组实际上立即衰减到指针(除了极少的特定上下文),这就是为什么0, arr表达式的结果具有char *类型的原因。它相当于0, (char *) arr

在C ++语言中,数组保持它们的“数组”更长。在,运算符数组的上下文中使用时,不会衰减为指针(并且左值不会衰减为rvalues),这就是为什么在C ++中0, arr表达式的类型仍为char[100]

这就解释了该示例中sizeof行为的差异。 ?:运算符是运算符的另一个示例,它演示了衰减行为的类似差异,即sizeof(0 ? arr : arr)将在C和C ++中给出不同的结果。基本上,这一切都源于C运算符通常不保留其操作数的左值。很多运算符都可以用来证明这种行为。

答案 3 :(得分:5)

这不是sizeof两个论点。 sizeof是一个运算符,而不是一个函数。

考虑(0, arr)是使用逗号运算符的表达式,其他所有内容都将落实到位。

答案 4 :(得分:3)

sizeof没有两个参数。但它也不是一个功能, 所以(...)不分界函数参数,它们只是一个 语法的可选部分,并强制执行分组。当你写作 sizeof(0, arr)sizeof的参数是单个表达式0, arr。带有逗号运算符的单个表达式,用于计算 逗号左边的表达式抛出它的值(但不是它的值) 副作用),然后评估逗号右边的表达式, 并使用其值作为完整表达式的值。

我不确定C,但这可能是一个区别 汉语语言。在C ++中,除非发生数组到指针的转换 这是必需的;在C中,如果我没记错的话,标准就说了 总是发生在某些情况下。包括作为 sizeof的运算符。在这种情况下,因为逗号运算符没有 对其操作数的类型有限制 数组到指针的转换不会发生在C ++中。在C中,一个 逗号运算符的operatand没有在例外中列出,所以 数组到指针的转换确实发生了。 (在这种情况下,阵列 是逗号运算符的操作数,而不是sizeof的操作数。)

答案 5 :(得分:2)

查看可能发生的事情的最佳方法是查看标准中的语法。如果我们查看草案C99标准部分6.5.3 一元运算符 1 ,我们可以看到sizeof的语法是:

sizeof unary-expression
sizeof ( type-name )

所以第二个不适用,但sizeof unary-expression在这种情况下如何适用?如果我们从草案标准中查看A.2.1 表达式部分,并按照这样的方式处理语法:

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

我们在表达式周围得到括号,现在我们只需要查看6.5.17 逗号运算符<的逗号运算符的语法/ em>我们看到了:

expression:
  assignment-expression
  expression , assignment-expression

所以我们现在有:

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

表达式赋值表达式都可以将我们带到 primary-expression ,它具有以下语法:

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

0常量arr标识符,所以我们有:

 sizeof( constant , identifier )

那么逗号运算符在这里做什么?第6.5.17 2 表示:

  

逗号运算符的左操作数被计算为void表达式;有一个   评估后的序列点。然后评估右操作数;结果有其类型和价值。 97)

因为逗号运算符不是数组未转换为指针的异常之一,它会产生一个指针(这将在 6.3.2.1 Lvalues,数组中涵盖和函数指示符)这意味着我们最终得到:

sizeof( char * )

C ++ 中,语法非常相似,所以我们在同一个地方结束,但逗号运算符的工作方式不同。 C ++草案标准部分5.18 逗号运算符表示:

  

[...]结果的类型和值是右操作数的类型和值;结果与右操作数[...]

具有相同的值类别

所以并不需要数组到指针的转换,因此我们最终得到:

sizeof( char[100] ) 

答案 6 :(得分:1)

正如几位已经说过的那样,我只想添加一个东西,sizeof是一个运算符,它采用表达式或强制转换表达式。 出于这个原因,我习惯于将paranthesis写为sizeof only ,如果它是一个强制转换表达式。

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

我会写

sizeof arr 
sizeof v

但是

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

我对return没有括号做同样的事情,因为它不是函数调用,如果我把括号括起来,因为下面的表达式需要它们。