首页 文章

为什么sizeof(x)不会增加x?

提问于
浏览
478

这是在dev c windows中编译的代码:

#include <stdio.h>

int main() {
    int x = 5;
    printf("%d and ", sizeof(x++)); // note 1
    printf("%d\n", x); // note 2
    return 0;
}

执行 note 1 后,我希望 x 为6 . 但是,输出是:

4 and 5

谁能解释为什么 xnote 1 后没有增加?

9 回答

  • 10

    来自C99 Standard(重点是我的)

    6.5.3.4/2 sizeof运算符产生其操作数的大小(以字节为单位),可以是表达式或类型的带括号的名称 . 大小由操作数的类型确定 . 结果是整数 . 如果操作数的类型是可变长度数组类型,则计算操作数;否则,不评估操作数,结果是整数常量 .

  • 19

    sizeofcompile-time operator ,因此在编译时 sizeof 并且其操作数被结果值替换 . 操作数是 not evaluated (除非它是一个可变长度数组);只有 type 的结果很重要 .

    short func(short x) {  // this function never gets called !!
       printf("%d", x);    // this print never happens
       return x;
    }
    
    int main() {
       printf("%d", sizeof(func(3))); // all that matters to sizeof is the 
                                      // return type of the function.
       return 0;
    }
    

    输出:

    2
    

    因为 short 在我的机器上占用2个字节 .

    将函数的返回类型更改为 double

    double func(short x) {
    // rest all same
    

    8 作为输出 .

  • 0

    sizeof(foo) 尝试在编译时很难发现表达式的大小:

    6.5.3.4:

    sizeof运算符生成其操作数的大小(以字节为单位),该操作数可以是表达式或类型的带括号的名称 . 大小由操作数的类型确定 . 结果是整数 . 如果操作数的类型是可变长度数组类型,则计算操作数;否则,不评估操作数,结果是整数常量 .

    简而言之:可变长度数组,在运行时运行 . (注意:Variable Length Arrays是一个特定的功能 - 不是用 malloc(3) 分配的数组 . )否则,只计算表达式的类型,并在编译时计算 .

  • 177

    sizeof 是一个编译时内置运算符,不是函数 . 在没有括号的情况下可以使用它变得非常清楚:

    (sizeof x)  //this also works
    
  • 10

    Note

    这个答案是从一个副本合并而来,这解释了迟到的日期 .

    Original

    variable length arrays之外,sizeof不评估其参数 . 我们可以从C99标准部分草案中看到这一点 6.5.3.4 运营商第2段的尺寸说:

    sizeof运算符生成其操作数的大小(以字节为单位),该操作数可以是表达式或类型的带括号的名称 . 大小由操作数的类型确定 . 结果是整数 . 如果操作数的类型是可变长度数组类型,则计算操作数;否则,不评估操作数,结果是整数常量 .

    评论(现已删除)询问是否会在运行时评估此类内容:

    sizeof( char[x++]  ) ;
    

    事实上,这样的事情也会奏效(See them both live):

    sizeof( char[func()]  ) ;
    

    因为它们都是可变长度数组 . 虽然,我认为其中任何一个都没有太多实际用途 .

    注意,draft C99 standard部分 6.7.5.2 数组声明符第4段中介绍了可变长度数组:

    [...]如果size是一个整型常量表达式,并且元素类型具有已知的常量大小,则数组类型不是可变长度数组类型;否则,数组类型是可变长度数组类型 .

    Update

    在C11中,VLA案例的答案发生了变化,在某些情况下,未指定是否评估了大小表达式 . 来自 6.7.6.2 部分的数组声明符说:

    [...]如果size表达式是sizeof运算符的操作数的一部分,并且更改size表达式的值不会影响运算符的结果,则无法指定是否计算size表达式 .

    例如,在这种情况下(see it live):

    sizeof( int (*)[x++] )
    
  • 0

    由于未评估 sizeof 运算符的操作数,您可以执行以下操作:

    int f(); //no definition, which means we cannot call it
    
    int main(void) {
            printf("%d", sizeof(f()) );  //no linker error
            return 0;
    }
    

    在线演示:http://ideone.com/S8e2Y

    也就是说,如果仅在 sizeof 中使用它,则不需要定义函数 f . 这种技术主要用于C模板元编程,因为即使在C中,也不会评估 sizeof 的操作数 .

    为什么这样做?它起作用,因为 sizeof 运算符不对值进行操作,而是对表达式的类型进行操作 . 因此,当您编写 sizeof(f()) 时,它会对表达式 f() 的类型进行操作,这只是函数 f 的返回类型 . 返回类型总是相同的,无论函数在实际执行时返回什么值 .

    在C中,你甚至可以这样:

    struct A
    {
      A(); //no definition, which means we cannot create instance!
      int f(); //no definition, which means we cannot call it
    };
    
    int main() {
            std::cout << sizeof(A().f())<< std::endl;
            return 0;
    }
    

    然而看起来,在 sizeof 中,我首先通过编写 A() 来创建 A 的实例,然后通过编写 A().f() 来调用实例上的函数 f ,但是没有发生这样的事情 .

    演示:http://ideone.com/egPMi

    这是另一个解释 sizeof 的其他有趣属性的主题:

  • 46

    编译期间不能执行 . 所以 ++i / i++ 不会发生 . 此外 sizeof(foo()) 不会执行该功能但返回正确类型 .

  • 508

    sizeof() 运算符仅给出数据类型的大小,它不计算内部元素 .

  • 33

    sizeof 在编译时运行,但 x++ 只能在运行时进行评估 . 为了解决这个问题,C标准规定不评估 sizeof 的操作数(除了VLA) . C标准说:

    如果操作数[sizeof]的类型是可变长度数组类型,则计算操作数;否则,不评估操作数,结果是整数常量 .

相关问题