sizeof是关键字不是函数
在 Pascal 语言中,sizeof() 是一种内存容量度量函数,功能是返回一个变量或者类型的大小(以字节为单位);
在 C 语言中,sizeof() 是一个判断数据类型或者表达式长度的运算符。
语法sizeof有两种形式:
sizeof(类型)----------sizeof(int)
sizeof 对象 ----------sizeof i//i为int型变量
我们可以在int前面加unsigned、const关键字,不能加sizeof。
sizeof在计算变量所占空间大小时,括号可以省略,而计算类型(模子)大小时不能省略。
且一般情况下,sizeof是在编译时求值,所以sizef(i++)
不会引起副作用,但由于sizeof(i++)
,sizeof(i)
的结果是一样的,所以没有必要且不允许写这样的代码。
sizeof操作符里面不要有其他运算,否则不会达到预期的目的。
在C99中,计算柔性数组所占空间大小时,sizeof是在运行时求值,此为特例。
指针变量的sizeof
所以在32位计算机中,一个指针变量的返回值必定是4(注意结果是以字节为单位),但是,在64位系统中指针变量的sizeof结果为8。
void fun1(char a[3])
{
int b = sizeof(a);
}
void fun2(char a[])
{
int c = sizeof(a);
}
void fun3(char *a)
{
int d = sizeof(a);
}
b,c,d的值为多少?
b=c=d=4。
这里函数参数a已不再是数组类型,而是蜕变成指针,相当于char* a,为什么仔细想想就不难明白,我们调用函数fun1时,程序会在栈上分配一个大小为3的数组吗?不会!数组是“传址”的,调用者只需将实参的地址传递过去,所以a自然为指针类型(char*),c的值也就为4。
结构体变量的sizeof
struct In
{
int i;
char ch;
};
int a = sizeof(struct In);
a的值为8。字节对齐
为什么需要字节对齐计算机组成原理教导我们这样有助于加快计算机的取数速度,否则就得多花指令周期了。为此,编译器默认会对结构体进行处理(实际上其它地方的数据变量也是如此),让宽度为2的基本数据类型(short等)都位于能被2整除的地址上,让宽度为4的基本数据类型(int等)都位于能被4整除的地址上,以此类推。这样,两个数中间就可能需要加入填充字节,所以整个结构体的sizeof值就增长了。
字节对齐的细节和编译器实现相关,但一般而言,满足三个准则:
- 结构体变量的首地址能够被其最宽基本类型成员的字节大小所整除
- 结构体每个成员相对于结构体首地址的偏移量(offset)都是该最简单成员字节大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal padding)
- 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节(trailing padding)
struct S1
{
int i;
char c;
}; 8
struct S3
{
char c1;
S1 s;
char c2; 16
};
S1的最宽简单成员的类型为int
,S3在考虑最宽简单类型成员时是将S1“打散”看的,所以S3的最宽简单类型为int
,这样,通过S3定义的变量,其存储空间首地址需要被4整除,整个sizeof(S3)的值也应该被4整除。
c1的偏移量为0,s的偏移量呢这时s是一个整体,它作为结构体变量也满足前面三个准则,所以其大小为8,偏移量为4,c1与s之间便需要3个填充字节,而c2与s之间就不需要了,所以c2的偏移量为12,算上c2的大小为13,13是不能被4整除的,这样末尾还得补上3个填充字节。最后得到sizeof(S3)的值为16。
结构体的大小等于最后一个成员的偏移量加上其大小再加上末尾的填充字节数目。