【问题标题】:Is sizeof(void()) a legal expression?sizeof(void()) 是合法的表达式吗?
【发布时间】:2017-01-09 17:33:48
【问题描述】:

[5.3.3/1],我发现:

sizeof 运算符不得应用于具有函数或不完整类型的表达式

[3.9/5]我发现:

不完整定义的对象类型和 cv void 是不完整的类型

无论如何,对于sizeof 不计算它的操作数,我会说sizeof(void()) 是一个合法的表达式(实际上GCC 编译它,结果是1)。
另一方面,从here 开始,在讨论sizeof 时没有提到void,既没有提到大小为1 的类型,也没有在具有定义的实现的列表中大小。

因此问题是:sizeof(void()) 是合法表达吗?
是否保证大小等于 1?
或者它是导致 UB 的合法表达,仅此而已?

【问题讨论】:

  • CppReference sizeof operator 说这是一个错误
  • GCC 曾经有(并且可能仍然有)扩展名 sizeof(void) == 1
  • 我的 g++ 副本是这样写的:warning: invalid application of ‘sizeof’ to a function type [-Wpointer-arith]
  • 也许应用程序会抑制错误/警告消息
  • @skypjack 答案是一样的——因此没有。

标签: c++ language-lawyer sizeof void


【解决方案1】:

void() 是一个函数类型(它是一个不带参数且不返回任何内容的函数),因此它不是sizeof() 中的有效类型。

【讨论】:

  • 不是解释成decltype(void())中的吗(注意这里不是函数类型)?我确实会这么说。为什么它们不同?
  • @skypjack 当您使用带有decltype 的函数类型时,它会给出返回类型的类型。在void() 的情况下,返回类型是void,所以这是decltype(void()) 的类型。
  • 那么为什么decltype(void(void))decltype(int(int)) 都不起作用?不,在使用decltype 时它不是函数类型。在sizeof的情况下我不能说。
  • @skypjack 我想我现在明白了,decltype 需要一个表达式,而不是一个类型。 void() 在这里实际上不是一个类型,而是一个表达式,一个 C 风格的转换(就像 int(12.34) 一样)void(void) 不是一个表达式,因此它不起作用。编译器如何解析不同的东西取决于上下文,当它需要一个类型时它会解析为一个类型,当它需要一个表达式时它会解析为一个表达式。 sizeof()(带括号)首先需要一个类型,否则将被解析为带括号的表达式。
  • cppreference sizeof 提供了sizeof 操作符的示例用法,它清楚地表示函数大小sizeof(void()),并说这是一个错误,这里,@ 987654340@,我觉得真的是函数类型。
【解决方案2】:

通过查看CppReference.com - sizeof operator,文档字面意思是:

sizeof 不能与 函数类型、不完整类型或 位域glvalues。

由于void()是一个函数类型,那么sizeof(void())不是一个合法的表达式。

在他们的用法示例中,我们可以在这一行看到他们的错误注释:

std::cout << "size of function: " << sizeof(void()) << '\n'; // error

【讨论】:

    【解决方案3】:

    另外,如果你编译代码,比如下面的例子:

    #include <iostream>
    
    int main()
    {
       std::cout << sizeof(void());
    }
    

    代码正确编译并产生值 1,但如果您查看编译,您会看到:

    main.cpp:在函数'int main()'中:

    main.cpp:5:29: 警告:对函数类型 [-Wpointer-arith] 无效应用“sizeof”

    std::cout

    所以,sizeof() 显然不适用于函数类型,因此代码会产生警告。这是无效的。


    Code here

    【讨论】:

      【解决方案4】:

      一个小前提。

      问题源于对sizeof 运算符的误解。
      事实上,OP 认为 void() 是在 sizeof 的上下文中具有不完整类型的表达式,并且问题本身可以理解为 - 为什么 sizeof 接受表达式 void(),这是一个不完整的类型并且不应该接受工作草案中提到的
      这就是为什么实际上提到了[3.9/5],否则就没有意义了。

      也就是说,这个问题实际上包含两个有趣的问题:

      • 为什么sizeof(void()) 不合法?
        这是标题本身的实际问题。

      • 为什么sizeof((void())) 不合法?
        这是 OP 的预期问题。

      答案如下:

      • sizeof(void()) 中的void() 被解释为一个函数类型,它与[5.3.3/1] 的格式不正确(强调我的):

        sizeof 运算符不得应用于具有函数或不完整类型的表达式,应用于此类类型的括号名称,[...]

      • sizeof((void())) 中的(void()) 是一个具有不完整类型 void 的表达式(请注意,sizeof 是一个未评估的上下文),它与[5.3.3/1] 的格式不正确(强调我的):

        sizeof 运算符不得应用于具有函数或不完整类型的表达式,应用于此类类型的括号名称,[...]

      在这两种情况下,GCC 都会编译带有警告的代码。

      【讨论】:

        【解决方案5】:

        正如这里的文档中已经强调的那样 http://en.cppreference.com/w/cpp/language/sizeof

        备注

        sizeof() 不能与函数类型、不完整类型或位域glvalues 一起使用。

        由于void()是一个函数类型,所以它不是sizeof()的有效类型

        注意:

        void() 是一个不带参数且不返回任何内容的函数

        引用文档中的示例:

        //<< "size of function: " << sizeof(void()) << '\n'  // error
        

        所以回答你的问题:

        1)不,这不是合法的表达方式。

        2)它将显示为 1 ,但会显示警告

        3) 与 1) 相同。

        【讨论】:

        • 2) 它确实可以编译,这在原始问题中有说明
        【解决方案6】:

        C99 参考 NO

        在文档6.5.3.4 sizeof 操作符部分下说明:

        sizeof 运算符不得应用于具有函数类型或不完整类型的表达式、此类类型的括号名称或指定位域成员的表达式。

        根据6.2.5 类型部分的第19和20项:

        1. void 类型包含一组空值;它是不完整的类型,无法完成。
        2. ...函数类型描述具有指定返回类型的函数。函数类型的特征在于它的返回类型以及它的参数的数量和类型。 一个函数类型被称为是从它的返回类型派生的,如果它的返回类型是 T,这个函数类型有时被称为“函数返回 T”。从返回类型构造函数类型称为“函数类型派生”。

        因此 void() 是从不完整类型派生的函数类型,并且它作为 sizeof 的操作数是非法的。也就是说,它的返回将取决于编译器的实现,并且不保证任何返回值

        C99 Standard

        【讨论】:

        • 查看问题的标签。
        • 感谢您的反馈,但是当前 C++ 标准第 3.9.1 节第 9 项中对 void 类型的定义与第 5.3.3 节第 1 项中关于 sizeof 运算符的定义没有区别: sizeof 运算符不应应用于具有函数或不完整类型的表达式... [open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4296.pdf]
        • 当然,但是对于标记为 C++ 的问题,值得一提的是正确的参考。就是这样。
        猜你喜欢
        • 1970-01-01
        • 2021-12-04
        • 2013-09-19
        • 1970-01-01
        • 2021-12-06
        • 1970-01-01
        • 1970-01-01
        • 2015-02-27
        相关资源
        最近更新 更多