【问题标题】:sizeof taking two argumentssizeof 接受两个参数
【发布时间】:2011-09-13 23:11:47
【问题描述】:

在 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)100sizeof(0, arr)sizeof(char*)sizeof(0, arr)sizeof(arr) 在 C++ 中都是 100

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


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

【问题讨论】:

  • 其实IS在说逗号操作符,但是我还是不明白是怎么回事。
  • 有趣。我从未见过 sizeof 有 2 个参数。它被定义为可选使用() 的一元运算符,这可以排除多个参数。
  • @PeterRowell:没错。这里传递给sizeof 的表达式使用了逗号运算符。即sizeof x,其中x 是表达式(0, arr)
  • 我采用了与现有答案有所不同的方法,我认为这可能更有趣。

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


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    这不是sizeof 采用两个参数。 sizeof 是一个运算符,而不是一个函数。

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

    【讨论】:

    • 问题是“明显的后备是逗号运算符,但我不这么认为”,你得到了 4 票赞成“考虑......逗号运算符,其他一切都到位“?
    • @Michael:至少,我是说 OP 想错了。
    • +1 表示sizeof 是一个运算符。它需要一个表达式或一个强制转换表达式。
    【解决方案3】:

    在 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

    所以 comma 操作符让你感觉有很多参数。这里 comma 是一个操作符,但是在函数调用中,comma 不是一个操作符,它只是一个参数分隔符。

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

    所以sizeof(a,b,c,d), 运算符的结果的type 进行操作,完全一样,sizeof(1+2+3+4) 在结果的type 上进行操作的+ 运营商。

    还请注意,您不能sizeof(int, char, short),正是因为逗号运算符不能对类型进行操作。它只对 value 起作用。我认为,sizeof 是 C 和 C++ 中唯一可以对 types 进行操作的运算符。在 C++ 中,还有一个运算符可以对 types 进行操作。它的名字是typeid

    【讨论】:

    • 关于最后一段:C++ 中的new 运算符也对类型进行操作。
    【解决方案4】:

    它是一个逗号运算符。而且您所说的差异与sizeof 完全无关。区别实际上在于 C 和 C++ 语言之间的左值到右值、数组到指针以及类似的衰减行为。

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

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

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

    【讨论】:

    • +1 没有说这种行为是因为 , 会产生一个非左值,并且正确地说这是因为 C 的触发快乐。并且没有说左值到右值转换将对此负责。
    【解决方案5】:

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

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

    【讨论】:

      【解决方案6】:

      正如一些人已经说过的,我只想添加一件事,sizeof 是一个接受表达式或强制转换表达式的运算符。 出于这个原因,我养成了将括号写入 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 *)
      

      我对@9​​87654324@ 做同样的事情,没有括号,因为它不是函数调用,如果我加上括号,那是因为下面的表达式需要它们。

      【讨论】:

        【解决方案7】:

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

        sizeof unary-expression
        sizeof ( type-name )
        

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

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

        我们得到了一个表达式周围的括号,现在我们只需要查看6.5.17部分中逗号运算符的语法逗号运算符 我们看到了:

        expression:
          assignment-expression
          expression , assignment-expression
        

        所以我们现在有:

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

        expressionassignment-expression 都可以将我们带到 primary-expression,其语法如下:

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

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

         sizeof( constant , identifier )
        

        那么逗号操作符在这里做了什么?第6.5.172说:

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

        因为逗号运算符不是数组不转换为指针的例外之一,所以它产生一个指针(这在部分中有所介绍6.3.2.1左值、数组和函数指示符),这意味着我们最终得到:

        sizeof( char * )
        

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

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

        so 和 array-to-pointer 转换不是必需的,所以我们最终得到:

        sizeof( char[100] ) 
        

        【讨论】:

          猜你喜欢
          • 2014-12-13
          • 2010-12-06
          • 1970-01-01
          • 2012-10-22
          • 2023-03-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-01-11
          相关资源
          最近更新 更多