下面是在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之后没有增加吗?
当前回答
Sizeof (foo)在编译时非常努力地发现表达式的大小:
6.5.3.4:
sizeof操作符产生其操作数的大小(以字节为单位),该操作数可以是 表达式或类型的圆括号名称。尺寸是由类型决定的 操作数。结果是一个整数。如果操作数的类型是可变长度数组 类型,则对操作数求值;否则,操作数不求值,结果为 整型常量。
简而言之:可变长度数组,在运行时运行。(注意:可变长度数组是一个特定的特性——不是由malloc(3)分配的数组。)否则,只计算表达式的类型,并在编译时计算表达式的类型。
其他回答
Sizeof在编译时运行,但x++只能在运行时求值。为了解决这个问题,c++标准规定不计算sizeof的操作数。C标准说:
如果操作数[of sizeof]的类型是变长数组类型,则计算该操作数;否则,操作数不计算,结果为整数常数。
Sizeof (foo)在编译时非常努力地发现表达式的大小:
6.5.3.4:
sizeof操作符产生其操作数的大小(以字节为单位),该操作数可以是 表达式或类型的圆括号名称。尺寸是由类型决定的 操作数。结果是一个整数。如果操作数的类型是可变长度数组 类型,则对操作数求值;否则,操作数不求值,结果为 整型常量。
简而言之:可变长度数组,在运行时运行。(注意:可变长度数组是一个特定的特性——不是由malloc(3)分配的数组。)否则,只计算表达式的类型,并在编译时计算表达式的类型。
由于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()只是函数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(),然后调用实例上的函数f,通过编写A().f(),但这样的事情没有发生。
演示:http://ideone.com/egPMi
下面是另一个主题,它解释了sizeof的其他一些有趣的属性:
Sizeof取两个参数
来自C99标准(重点是我的)
6.5.3.4/2 sizeof操作符产生其操作数的大小(以字节为单位),该操作数可以是表达式或带括号的类型名。大小由操作数的类型决定。结果是一个整数。如果操作数的类型是变长数组类型,则计算该操作数;否则,操作数不计算,结果为整数常数。
Sizeof()操作符只给出数据类型的大小,它不计算内部元素。