內存對齊問題--vs2010下位域結構體對齊規則

請寫出一下代碼的輸出結果:

// interface.cpp : 定義控制檯應用程序的入口點。
//內存對齊
#include "stdafx.h"
#include <stdio.h>
#include <memory.h>
struct s1
{
	int i:8;
	char j:4;
	int a:4;
	double b;
};

struct s2
{
	int i:8;
	int j:4;
	double b;
	int a:4;
};
struct s3
{
	int i;
	char j;
	double b;
	int a;
};
struct s4
{
	int i:8;
	int j:4;
	int a:3;
	double b;
};
struct s5
{
	int i:8;
	int j:4;
	double b;
	int a:3;
};

struct name1
{
	char str;
	short x;
	int num;
};
struct name2
{
	char str;
	int num;
	short x;
};

int _tmain(int argc, _TCHAR* argv[])
{
	memset((struct s1 *)(0x0012FF48),0,sizeof(struct s1));
     struct	s1 s;
	s.i=1;
	s.j=2;
	s.a=3;
	s.b=3;
	printf("%d\t",sizeof(s1));
	printf("%d\t",sizeof(s2));
	printf("%d\t",sizeof(s3));
	printf("%d\t",sizeof(s4));
	printf("%d\t",sizeof(s5));
	printf("%d\t",sizeof(name1));
	printf("%d\t",sizeof(name2));
	return 0;
}

按照位域內存對齊規則並參考http://www.cppblog.com/snailcong/archive/2009/03/16/76705.html,分析得知sizeof(s1)=16,而vs2010給出的答案是24,糾結了一下午也沒給出一個明確的答案,先把疑問寫出來,慢慢來求解。
對於比較難解決的問題,最好不要依賴printf,直接按F10,在監視1看了下變量s的地址是0x0012FF48,所以在memset裏會出現0x0012FF48這個地址,爲了把變量s在內存中所佔區域清零,然後在內存1中查看0x0012FF48起始的內存塊,如下圖所示:

從圖中可以看出vs內存對齊規則是4(int)+1(char)+3(擴展)+4(int)+4(擴展)+8(double),很明顯就沒按位域對齊規則來存儲,而是按照普通的一個結構體來進行內存對齊,難道這是vs2010的一個小bug?待求解!
在網上搜索了一番,終於解開了謎題,http://www.diybl.com/course/3_program/c++/cppsl/20090311/160450.html# 這篇文章寫得很好,解釋的很清楚,對於位域存儲規則的處理不同編譯器處理規則不一樣。(以下文字來自於http://www.diybl.com/course/3_program/c++/cppsl/20090311/160450.html#)
如果結構體中含有位域(bit-field),那麼VC中準則又要有所更改:
1) 如果相鄰位域字段的類型相同,且其位寬之和小於類型的sizeof大小,則後面的字段將緊鄰前一個字段存儲,直到不能容納爲止;
2) 如果相鄰位域字段的類型相同,但其位寬之和大於類型的sizeof大小,則後面的字段將從新的存儲單元開始,其偏移量爲其類型大小的整數倍;
3) 如果相鄰的位域字段的類型不同,則各編譯器的具體實現有差異,VC6採取不壓縮方式(不同位域字段存放在不同的位域類型字節中),Dev-C++和GCC都採取壓縮方式;

發佈了16 篇原創文章 · 獲贊 9 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章