sizeof(a)返回的是系统对在内存中对a分配的内存空间大小,单位为字节。不同操作系统(window和Linux)
以及不同位数(32位或64位)的系统内存分配策略(字节对齐)不同,因此sizeof的返回值也不相同。接下来我
们针对Linux和Window两种操作系统进行分析。
在win32位和win64位机子上,各个基本对象所占空间大小如图所示:
C声明 | Intel数据类型 | X86-64 | IA32 |
char | 字节 | 1 | 1 |
short | 字 | 2 | 2 |
int | 双字 | 4 | 4 |
long int | 四字 | 8 | 4 |
long long int | 四字 | 8 | 8 |
char * | 四字 | 8 | 4 |
float | 单精度 | 4 | 4 |
double | 双精度 | 8 | 8 |
long double | 扩展精度 | 16 | 12 |
许多计算机系统对基本数据类型合法地址作出了一些限制,要求某种类型对象的地址必须为某个K(通常为2、4
或8)的倍数。例如:假设一个操作系统总是从内存中取出8个字节数据,则其地址必须是8字节对齐的。
Linux沿用的对齐政策是,2字节数据类型(例如short)的地址必须是2的倍数,而较大的数据类型(例如int,
int*,float和double)的地址必须是4的倍数,这个要求就意味着一个short类型对象的地址最低位必须等于0.而int
类型的对象和指针的地址的最低位必须都是0.
例如在Linux下,有如下数据结构:
struct P1
{
char w[3];
short s[3];
};
则该数据结构经过编译后存储方式如下(2字节对齐):上面数字为偏移量,下面为数据
由于数据结构中含有short类型数据,所以short类型数据地址必须为2的倍数。则在Linux下,运用sizeof求得
的数据结构大小为:
sizeof(P1) = 10
考虑下面结构体
struct P2
{
int i;
char c;
char d;
int j;
};
其存储结构如下(8字节对齐):
数据结构中存在int型,其存储时是按照4字节对齐的,则sizeof(P2)=12.
对于Microsoft WIndows的对齐比较严格:任何K字节基本对象的地址都必须是K的倍数,K=2、4或者8.特别地,
它要求一个double或者long long类型数据的地址应该是8的倍数。这种要求提高了存储器性能,而代价是浪费了一
些空间。Linux中8字节数据在4字节边界对齐。而数据类型long double,无论在Linux上还是window上都是4字节
对齐的。同理,在32位Windows下,仍然
struct P3
{
char c;
short s;
};
则其存储结构为:
存在的最大数据对象short为2字节,因此存储结构为2字节对齐,则sizeof(P3)= 4
struct P4
{
char c;
short s;
int i;
};
其存储结构为:
则sizeof(P4) = 8.
对于下面这个数据结构,由于存在double和long long类型,所以其存储时按照8字节对齐
struct foo
{
char* a;
short b;
double c;
char d;
float e;
char f;
long long g;
void* h;
};
分析其存储结构:
由于C为double类型,所以其地址必须为8的倍数,古需要在b后面填充两个字节。而e为float类型,其地址需要
为4的倍数,因此17-20之间字节需要填充,而g为long long型,其地址必须为8的倍数,所以f后边需要填充7
个字节。而void*占用四个字节,需要将其八字节对齐,因此需要补齐四字节。所以sizeof(foo) = 48.对于Win64
位的机器,其指针所占字节为8字节,因此当结构中存在指针时,也需要八字节对齐。