这是在dev c ++窗口中编译的代码:
#include <stdio.h>
int main() {
int x = 5;
printf("%d and ", sizeof(x++)); // note 1
printf("%d\n", x); // note 2
return 0;
}
我预计x
在执行注释1后将为6 。但是,输出为:
4 and 5
谁能解释为什么注释1x
之后不增加?
这是在dev c ++窗口中编译的代码:
#include <stdio.h>
int main() {
int x = 5;
printf("%d and ", sizeof(x++)); // note 1
printf("%d\n", x); // note 2
return 0;
}
我预计x
在执行注释1后将为6 。但是,输出为:
4 and 5
谁能解释为什么注释1x
之后不增加?
Answers:
来自C99标准(重点是我的)
6.5.3.4/2
sizeof运算符产生其操作数的大小(以字节为单位),该操作数可以是表达式或类型的括号名称。大小由操作数的类型确定。结果是一个整数。如果操作数的类型是可变长度数组类型,则对操作数求值;否则,不评估操作数,结果为整数常量。
N
从stdin和make中读取int array[N]
。这是C99的功能之一,在C ++中不可用。
sizeof(int[++x])
(确实是一个非常糟糕的主意)++
进行评估。
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
因为short
在我的机器上占用了2个字节。
将函数的返回类型更改为double
:
double func(short x) {
// rest all same
将给出8
作为输出。
注意
此答案是从重复副本中合并而成的,这解释了延迟日期。
原版的
除了可变长度数组, sizeof不会评估其参数。我们可以从C99标准草案6.5.3.4
的sizeof运算符第2段中看到这一点:
sizeof运算符产生其操作数的大小(以字节为单位),该操作数可以是表达式或类型的括号名称。大小由操作数的类型确定。结果是一个整数。如果操作数的类型是可变长度数组类型,则对操作数求值;否则,不评估操作数,结果为整数常量。
一个注释(现已删除)询问这样的事情是否会在运行时评估:
sizeof( char[x++] ) ;
确实可以,像这样的东西也可以工作(看到他们两个都活着):
sizeof( char[func()] ) ;
因为它们都是可变长度数组。虽然,我都没有发现任何实际用途。
注意,可变长度数组被覆盖在草案标准C99部6.7.5.2
组声明第4段:
[...]如果大小是整数常量表达式,并且元素类型具有已知的常量大小,则数组类型不是可变长度数组类型;否则,数组类型为可变长度数组类型。
更新资料
在C11中,答案针对VLA情况而改变,在某些情况下,不确定是否评估大小表达式。从“ 6.7.6.2
数组声明器”部分说:
在size表达式是sizeof运算符的操作数的一部分并且更改size表达式的值不会影响该运算符的结果的情况下,不确定是否评估size表达式。
例如,在这种情况下(现场观看):
sizeof( int (*)[x++] )
sizeof
它实际上是一个宏-它不创建代码,而是预先计算期望值并将其直接存入代码中。请注意,这是直到C99 的唯一行为,因为VBA并不存在(直到得到这个答案之前,我才真正听说过它们,信不信由你!)
sizeof (char[x++]);
,将使用值的x
其他方式做什么?x++
x
char[x++]
是VLA。char*
在我不熟悉的眼睛看来,它实际上就像是一个。
由于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
也就是说,f
如果sizeof
仅使用该函数,则无需定义该函数。该技术主要用于C ++模板元编程中,因为即使在C ++中,sizeof
也不会评估操作数。
为什么这样做?之所以起作用,是因为sizeof
运算符不对value进行运算,而是对表达式的类型进行运算。因此,在编写时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()
然后f
通过编写在实例上调用该函数A().f()
,但是没有发生这种情况。
演示:http : //ideone.com/egPMi
这是另一个主题,解释了的其他一些有趣的属性sizeof
:
在编译期间无法执行。所以++i
/ i++
不会发生。也sizeof(foo())
将不执行功能,但返回正确的类型。
sizeof
编译时常量表达式一样”吗?
sizeof()
运算符仅给出数据类型的大小,它不评估内部元素。
sizeof()
操作符是递归操作的,并且将获得容器中所有元素,类或结构的成员等的大小(以字节为单位)。您可以通过创建一个包含几个成员的简单类并轻松地向自己证明这一点。呼吁sizeof()
。(但是,其中的任何指针指针都看不到-的大小。)这一切都是在编译时发生的,正如其他注释者所指出的那样:sizeof()
不会对表达式内部的值求值。