下面是在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;
}
我期望在执行注释1后x为6。然而,输出结果是:
4 and 5
有人能解释一下为什么x在注释1之后没有增加吗?
下面是在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;
}
我期望在执行注释1后x为6。然而,输出结果是:
4 and 5
有人能解释一下为什么x在注释1之后没有增加吗?
当前回答
这一行:
printf("%d and ", sizeof(x++)); // note 1
导致乌兰巴托。%d期望类型int而不是size_t。获得UB后,行为是未定义的,包括写入标准输出的字节。
如果你想通过将%d替换为%zu或将值转换为int来解决这个问题,但不是两者都用,你仍然不会增加x,但这是一个不同的问题,应该在不同的问题中问。
其他回答
这一行:
printf("%d and ", sizeof(x++)); // note 1
导致乌兰巴托。%d期望类型int而不是size_t。获得UB后,行为是未定义的,包括写入标准输出的字节。
如果你想通过将%d替换为%zu或将值转换为int来解决这个问题,但不是两者都用,你仍然不会增加x,但这是一个不同的问题,应该在不同的问题中问。
来自C99标准(重点是我的)
6.5.3.4/2 sizeof操作符产生其操作数的大小(以字节为单位),该操作数可以是表达式或带括号的类型名。大小由操作数的类型决定。结果是一个整数。如果操作数的类型是变长数组类型,则计算该操作数;否则,操作数不计算,结果为整数常数。
Sizeof是一个编译时操作符,因此在编译时Sizeof及其操作数将被结果值替换。操作数根本不会被求值(除非它是一个变长数组);只有结果的类型是重要的。
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
As short在我的机器上占用了2个字节。
将函数的返回类型改为double:
double func(short x) {
// rest all same
将给出8作为输出。
Note
这个答案是从一个副本合并而来的,所以日期晚了。
原始
除了变长数组,sizeof不计算它的参数。我们可以从C99标准草案第6.5.3.4节sizeof运算符第2段中看到这一点,其中说:
sizeof操作符产生其操作数的大小(以字节为单位),该操作数可以是 表达式或类型的圆括号名称。尺寸是由类型决定的 操作数。结果是一个整数。如果操作数的类型是可变长度数组 类型,则对操作数求值;否则,操作数不求值,结果为 整型常量。
一个评论(现已删除)询问这样的东西是否会在运行时求值:
sizeof( char[x++] ) ;
确实是这样,像这样的东西也会起作用(看他们都活下来了):
sizeof( char[func()] ) ;
因为它们都是变长数组。不过,我觉得这两种方法都没什么实际用处。
注意,可变长度数组在C99标准草案第6.7.5.2节数组声明符第4段中涉及:
[…如果size是一个整数常量表达式,并且元素类型有一个已知的常量大小,则数组类型不是变长数组类型;否则,数组类型为变长数组类型。
更新
在C11中,VLA情况的答案会发生变化,在某些情况下,是否计算大小表达式是未指定的。在第6.7.6.2节中,数组声明符表示:
[…其中,size表达式是sizeof操作数的一部分 操作符和改变大小表达式的值将不会 影响运算结果的,不确定是否 计算大小表达式。
例如,在这样的情况下(看现场):
sizeof( int (*)[x++] )
Sizeof()操作符只给出数据类型的大小,它不计算内部元素。