为了能使
CPU
对变量进行高效快速的访问,变量的起始地址应该具有某些特性,
即所谓的 “ 对齐 ” 。例如对于 4 字节的 int 类型变量,其起始地址应位于 4 字节边界上,
即起始地址能够被 4 整除。变量的对齐规则如下( 32 位系统):
即所谓的 “ 对齐 ” 。例如对于 4 字节的 int 类型变量,其起始地址应位于 4 字节边界上,
即起始地址能够被 4 整除。变量的对齐规则如下( 32 位系统):
Type
Alignment
char
在字节边界上对齐
在字节边界上对齐
short (16-bit)
在双字节边界上对齐
在双字节边界上对齐
int and long (32-bit)
在 4 字节边界上对齐
在 4 字节边界上对齐
float
在 4 字节边界上对齐
在 4 字节边界上对齐
double
在 8 字节边界上对齐
在 8 字节边界上对齐
字节对齐的细节和具体编译器实现相关,但一般而言,满足三个准则:
1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除;
1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除;
2)
结构体每个成员相对于结构体首地址的偏移量都是成员大小的整数倍,如有需要编译器会在成
员之间加上填充字节;例如上面第二个结构体变量的地址空间。
3)
结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员
之后加上填充字节。
例如 :
例如 :
struct s1
{
char a;
short b;
char c;
};
在上述结构体中,
size
最大的是
short
,其长度为
2
字节,因而结构体中的
char
成员
a
、
c
都以
2
为单位对齐,
sizeof(s1)
的结果等于
6
;
a b c
s1 的内存布局 1* 11 1* (* 表示填充的字节 , 下同 )
若改为
struct s1
{
char a;
int b;
char c;
};
a b c
s1 的内存布局 1* 11 1* (* 表示填充的字节 , 下同 )
若改为
struct s1
{
char a;
int b;
char c;
};
其结果显然为
12
。
a b c
s1 的内存布局 1*** 1111 1***
2. 又如 :
struct S1{
char a;
long b;
};
struct S2 {
char c;
struct S1 d;
long long e;
};
sizeof(S2) 结果为 24;
分析如下 :
根据上面的分析 sizeof(s1)=8;
s1 的内存布局 a b
1*** 1111
S2 中 ,c 和 S1 中的 a 一样 , 按 1 字节对齐 , 而 d 是个结构 , 它是 8 个字节 , 它按什么对齐呢 ? 对
a b c
s1 的内存布局 1*** 1111 1***
2. 又如 :
struct S1{
char a;
long b;
};
struct S2 {
char c;
struct S1 d;
long long e;
};
sizeof(S2) 结果为 24;
分析如下 :
根据上面的分析 sizeof(s1)=8;
s1 的内存布局 a b
1*** 1111
S2 中 ,c 和 S1 中的 a 一样 , 按 1 字节对齐 , 而 d 是个结构 , 它是 8 个字节 , 它按什么对齐呢 ? 对
于结构来说
,
它的默认对齐方式就是它的所有成员使用的对齐参数中最大的一个
,S1
的就是
4.
所以
,
成员
d
就是按
4
字节对齐
.
成员
e
是
8
个字节
,
它是默认按
8
字节对齐
,
和指定的一样
,
所以它对到
8
字节
的边界上
,
这时
,
已经使用了
12
个字节了
,
所以又添加了
4
个字节的空
,
从第
16
个字节开始放置成员
e.
这时
,
长度为
24,
已经可以被
8(
成员
e
按
8
字节对齐
)
整除
.
这样
,
一共使用了
24
个字节
.
S2 的内存布局 c d e
1*** 1***1111**** 11111111
再看两个结构体成员比较复杂的例子 :
Typedef struct student
S2 的内存布局 c d e
1*** 1***1111**** 11111111
再看两个结构体成员比较复杂的例子 :
Typedef struct student
{
Char name[10]
;
Long sno;
Char sex;
Float score [4];
} STU;
sizeof(STU)=?
STU 的内存布局 name sno sex score
1111111111** 1111 1*** 1111111111111111
sizeof(STU)=10+2+4+1+3+16
如果我们把 STU 中的成员改一下顺序 :
Typedef struct student
sizeof(STU)=?
STU 的内存布局 name sno sex score
1111111111** 1111 1*** 1111111111111111
sizeof(STU)=10+2+4+1+3+16
如果我们把 STU 中的成员改一下顺序 :
Typedef struct student
{
Char name[10]
;
Char sex;
Long sno;
Float score [4];
} STU;
STU 的内存布局 name sex sno score
1111111111 1* 1111 1111111111111111
STU 的内存布局 name sex sno score
1111111111 1* 1111 1111111111111111
sizeof(STU)=10+2+4+16
注意:
注意:
1
)
对于空结构体,
sizeof
==
1
;因为必须保证结构体的每一个实例在内存中都
有独一无二的地址。
有独一无二的地址。
2
)
结构体的静态成员不对结构体的大小产生影响,因为静态变量的存储位置与
结构体的实例地址无关。
结构体的实例地址无关。
例如:
struct {static int I;} T;
sizeof(T) == 1;
struct {char a; static int I;} T1;
sizeof(T1) == 1;
sizeof(T) == 1;
struct {char a; static int I;} T1;
sizeof(T1) == 1;