Skip to content

Instantly share code, notes, and snippets.

@prife
Created October 2, 2012 07:26
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save prife/3817036 to your computer and use it in GitHub Desktop.
Save prife/3817036 to your computer and use it in GitHub Desktop.
ANSI C中struct型数据的内存布局与对齐问题
《ANSI C中struct型数据的内存布局与对齐问题》
楼主自述:本文是笔者的一篇读书笔记,原文见参考文献1。笔者从原文中获取了很多知识,并根据编译器输出做了进一步的总结。
下面是正文。
--------------------------------------------------------------------------------
在VS2005中,如果使用/zp指定了内存对齐的边界,将这个边界记为ZP
1. ANSI C标准规定结构体类型的对齐要求不能比它所有字段中要求最严格的那个宽松,可以更严格(但此非强制要求,VC7.1就仅仅是让它们一样严格)将struct所有字段中要求最严格的字段的对齐记为ST。
2. 如果没有指定ZP时,对结构体内的某个域(假设其基本数据类型为T)的对齐模数(也就是此域的对齐地址)就是T的大小,即sizeof(T)。如果指定了ZP,此时结构体每个feild的对齐地址为当前这个域的sizeof值与ZP的中较小的值。
3. 如果没有指定ZP时,结构体最终大小一定是ST的整数倍。当指定了ZP时,结构体大小一定是min(ST, ZP)的整数倍。
4. 如果结构体内含有数组,则此域的对齐地址为数组元素类新的sizeof大小与ZP中较小的值。
以下面将以如下所示结构体来讲解这几条准则的是如何作用的。
struct ms3
{
char a;
short b;
int c;
char d;
} MS3;
a. 不指定ZP
b的起始地址将是2字节对齐;
c的起始地址应该是4字节对齐的;
d的起始地址不需要对齐。
但是又由rule3,此时没有指定ZP,SP=4,所以最终结构体大小需要是4的倍数,这需要在d之后加3个字节。
struct ms3
{ //对齐地址
char a; // sizeof(char) = 1 //1
short b; // sizeof(short) = 2 //2
int c; // sizeof(int) = 4 //4
char d; // sizeof(char) = 1 //1
} MS3;
根据上面的分析可知,此时结构体的内存布局为
padding
|
V
+-+-+--+-----+-+----+
| |/| | | |////|
|a|/| b| c |d|////|
| |/| | | |////|
+-+-+--+-----+-+----+
Bytes: 1 1 2 2 4 1 3
sizeof(struct ms3) = (1+1) + 2 + 4 + (1 + 3) = 12;
b. 指定了ZP
读者一定要当心,rule2已经明确指出,此时结构体每个filed的对齐地址为当前这个域的sizeof值与ZP的中较小的值。
举例
b.1) zp = 2
struct ms3
{ //对齐地址
char a; // sizeof(char) = 1 //min(zp, 1) = 1
short b; // sizeof(short) = 2 //min(zp, 2) = 2
int c; // sizeof(int) = 4 //min(zp, 4) = 2
char d; // sizeof(char) = 1 //min(zp, 1) = 1
} MS3;
注意,此时根据rule3, 此时sizeof(struct ms3)需要是2的倍数,在例子a中它必须是4的倍数,读者一定要注意。
根据上面的注释,可知,此时结构体的内存布局为
padding
|
V
+-+-+--+-----+-+-+
| |/| | | |/|
|a|/| b| c |d|/|
| |/| | | |/|
+-+-+--+-----+-+-+
Bytes: 1 1 2 4 1 1
sizeof(struct ms3) = (1+1) + 2 + 4 + (1 + 1) = 10;
b.2) zp = 4,8,16时
struct ms3
{ //对齐地址
char a; // sizeof(char) = 1 //min(zp, 1) = 1
short b; // sizeof(short) = 2 //min(zp, 2) = 2
int c; // sizeof(int) = 4 //min(zp, 4) = 4
char d; // sizeof(char) = 1 //min(zp, 1) = 1
} MS3;
可以看出此时ms3的内存分布和默认情况下是一样的。
--------------------------------------------------------------------------------
练习:
struct P1 { int a; char b; int c; char d; };
struct P2 { int a; char b; char c; int d; };
struct P3 { short a[3]; char b[3]; };
struct P4 { short a[3]; char *b[3]; };
struct P5 { struct P2 *a; char b; struct P1 c[2]; };
struct P6 { struct P2 a; char b; struct P1 c[2]; };
struct P7 { char a; short b; int c; char d;};
结果
+-----------------------------------+-----------------------------+
| vs2005/win7 32bit/i3 | gcc/ubuntu12.04 32bi |
+----+-----+----+----+----+----+----+-----------------------------+
| |defau|zp1 |zp2 |zp4 |zp8 |zp16| |
+----+-----+-+--+----+----+----+----+ |
| P1 | 16 | 10 | 12 | 16 | 16 | 16 | |
| | | | | | | | |
| P2 | 12 | 10 | 10 | 12 |*12 | 12 | |
| | | | | | | | |
| P3 | 10 | 9 | 10 |*10 |*10 | 10 | |
| | | | | | | | |
| P4 | 20 | 18 | 18 | 20 |*20 | 20 | |
| | | | | | | | |
| P5 | 40 | 25 | 30 | 40 | 40 | 40 | |
| | | | | | | | |
| P6 | 48 | 31 | 36 | 48 | 48 | 48 | |
| | | | | | | | |
| P7 | 8 | 8 | 10 | 12 | 12 | 8 | |
+----+-----+----+----+----+----+----+-----------------------------+
根据前面总结的4条准则,我们就可以精确的分析得到上面的结果。对于上图打*号的地方,读者需要注意rule2的作用。
参考文献
[1] http://blog.csdn.net/soloist/article/details/213717
[2] http://msdn.microsoft.com/en-us/library/xh3e3fd0(v=vs.71).aspx
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment