37

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

char arr[100];

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

我找不到sizeof接受两个论点的文档。明显的后备是逗号运算符,但我不这么认为:sizeof(arr)在 C 中是100; sizeof(0, arr)sizeof(char*)。两者sizeof(0, arr)都在 C++ 中sizeof(arr)100

在这种情况下,我可能会错过 IS 的全部意义。任何人都可以帮忙吗?这类似于 09 年讨论的一个问题,但没有人提到 IS,而且我认为没有给出正确的答案。


编辑:实际上,IS 是在谈论逗号运算符。因此,由于某种原因,在 C 中(0, arr)返回 a char*,但char[100]在 C++ 中返回 a。为什么?

4

7 回答 7

48

在 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 个逗号运算符;就像 in 一样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

于 2011-06-13T14:19:55.417 回答
25

在 C 中,数组衰减为指针,因为逗号运算符与右值和左值相关的不同规范(不是唯一可以找到这种差异的地方)。在 C++ 中,数组保持为数组,从而产生正确的结果。

于 2011-06-13T14:16:01.260 回答
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 运算符通常不保留其操作数的左值性这一事实。许多运算符可用于演示此行为。

于 2011-06-13T14:25:58.303 回答
5

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

考虑这(0, arr)是一个使用逗号运算符的表达式,其他一切都到位。

于 2011-06-13T14:18:32.367 回答
4

查看此处可能发生的情况的最佳方法是查看标准中的语法。如果我们查看草案 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

expression:
  assignment-expression
  expression , assignment-expression

所以我们现在有:

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

表达式赋值表达式都可以将我们带到具有以下语法的主表达式:

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

and0是一个常数arr是一个标识符,所以我们有:

 sizeof( constant , identifier )

那么逗号运算符在这里做什么呢?第26.5.17节说:

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

因为逗号运算符不是数组不转换为指针的例外之一,它会产生一个指针(这在 6.3.2.1 Lvalues, arrays, and function designators部分中有介绍),这意味着我们最终得到:

sizeof( char * )

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

[...]结果的类型和值是右操作数的类型和值;结果与其右操作数具有相同的值类别[...]

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

sizeof( char[100] ) 
于 2014-02-26T04:45:27.783 回答
3

sizeof不接受两个论点。但它也不是一个函数,所以(...)不要分隔函数参数,它们只是语法的可选部分,并强制分组。编写 sizeof(0, arr)时,参数 tosizeof是单个表达式0, arr。带有逗号运算符的单个表达式,它计算逗号左边的表达式,抛出它的值(但不是它的副作用),然后计算逗号右边的表达式,并使用它的值作为完整的表达。

我不确定C,但这可能是语言之间的差异。在 C++ 中,除非需要,否则不会发生数组到指针的转换;在 C 中,如果我没记错的话,标准说它总是发生,除非在某些情况下。包括作为sizeof. 在这种情况下,由于逗号运算符对其操作数的类型没有限制,因此在 C++ 中不会发生数组到指针的转换。在 C 中,逗号运算符的操作数未列在异常中,因此确实发生了数组到指针的转换。(在这种情况下,数组是逗号运算符的操作数,而不是sizeof.)

于 2011-06-13T14:44:58.140 回答
1

正如一些人已经说过的,我只想添加一件事,sizeof 是一个接受表达式或强制转换表达式的运算符。出于这个原因,我养成了将括号写入 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没有括号的情况下做同样的事情,因为它不是函数调用,如果我加上括号,那是因为下面的表达式需要它们。

于 2011-06-27T10:18:26.593 回答