问题描述
谁能解释为什么这个程序打印 4 1 而不是 4 2?
不应该先执行优先级更高的预增量运算符并打印 4 2 吗?
#include <stdio.h>
int main() {
int a=1;
printf ("%ld %d",sizeof(++a),a);
return 0;
}
解决方法
虽然你已经得到了几个答案,但我想再提供一个,因为你的问题实际上包含三个不同的误解,我想把它们都说一下。
首先,sizeof
是一个特殊的运算符,根据定义,它不评估它的参数(即,无论它取什么大小的子表达式)。所以 sizeof(++a)
不会不增加 a
。 sizeof(x = 5)
不会不会将 5 分配给 x
。 sizeof(printf("Hello!"))
不会不打印“Hello”。
其次,如果去掉sizeof
,直接写
printf("%d %d",++a,a);
我们不能能够使用优先级来确定行为。优先级是一个重要的概念,但通常它不能帮助您弄清楚涉及 ++
的混淆操作的行为。
最后,也许令人惊讶的答案是,如果你写
printf("%d %d",a);
不可能弄清楚它会做什么。它基本上是未定义的。 (具体来说:在像 printf("%d %d",x,y)
这样的任何函数调用中,unspecified 参数被评估的顺序,所以你不知道是 x
还是 y
被评估首先——尽管有一个顺序。但是,当其中一个是 a
并且其中一个是 ++a
时,您会遇到这样的情况,即 a
都被修改并拥有它的值,因此无法知道是使用旧值还是新值,这使得表达式未定义。有关此问题的更多信息,请参阅 this question。)
附言正如莫斯科的@Vlad 所指出的那样,我忘记提及的另一个问题是:%ld
不是打印 sizeof
的结果的可靠方法,它是 size_t
类型的值。如果可以,您应该使用 %zu
,如果不能,则在转换为 %u
后使用 (unsigned)
。
来自 C 标准 *6.5.3.4 sizeof 和 alignof 运算符)
2 sizeof 运算符产生其操作数的大小(以字节为单位),即 可以是表达式或类型的括号名称。尺寸是 由操作数的类型决定。结果是一个整数。如果 操作数的类型是变长数组类型,操作数 被评估; 否则,不计算操作数并且结果 是一个整数常量。
所以 sizeof
运算符的任务是确定用作操作数的表达式的类型,然后知道其操作数的类型以返回该类型的对象的大小。如果操作数不是变长数组,则不计算用作操作数的表达式,并在编译时计算 sizeof
运算符返回的值。
因此这个电话
printf ("%ld %d",sizeof(++a),a);
相当于调用
printf ("%ld %d",sizeof( int ),a);
并且在您的系统中 sizeof( int )
等于 4
。
因此,使用什么表达式(除非使用其大小在运行时计算的可变长度数组)作为操作数并不重要。重要的是表达式的类型。例如你甚至可以写
printf ( "%zu %d\n",sizeof( ( ++a,++a ) ),a );
得到了相同的结果。
请注意,您应该使用用于 zu
类型值的转换说明符 size_t
而不是用于有符号值的 ld
。那是你需要写
printf ("%zu %d",a);
,
根据c99 standard,
sizeof() 运算符只考虑操作数的类型,它可能是表达式或类型的名称(即 int、double、float 等),而不是计算表达式时获得的值。
>因此,sizeof() 运算符中的操作数不是求值的。