黄色网页视频 I 影音先锋日日狠狠久久 I 秋霞午夜毛片 I 秋霞一二三区 I 国产成人片无码视频 I 国产 精品 自在自线 I av免费观看网站 I 日本精品久久久久中文字幕5 I 91看视频 I 看全色黄大色黄女片18 I 精品不卡一区 I 亚洲最新精品 I 欧美 激情 在线 I 人妻少妇精品久久 I 国产99视频精品免费专区 I 欧美影院 I 欧美精品在欧美一区二区少妇 I av大片网站 I 国产精品黄色片 I 888久久 I 狠狠干最新 I 看看黄色一级片 I 黄色精品久久 I 三级av在线 I 69色综合 I 国产日韩欧美91 I 亚洲精品偷拍 I 激情小说亚洲图片 I 久久国产视频精品 I 国产综合精品一区二区三区 I 色婷婷国产 I 最新成人av在线 I 国产私拍精品 I 日韩成人影音 I 日日夜夜天天综合

sizeof 用法

系統(tǒng) 2088 0

結(jié)構(gòu)體對(duì)齊的具體含義 ( #pragma pack )

#pragma pack (4)
class TestB
{
public:
int aa;
char a;
short b;
char c;
};
int nSize = sizeof(TestB);
  這里 nSize 結(jié)果為 12 ,在預(yù)料之中。

  現(xiàn)在去掉第一個(gè)成員變量為如下代碼:
#pragma pack (4)
class TestC
{
public:
char a;
short b;
char c;
};
int nSize = sizeof(TestC);
  按照正常的填充方式 nSize 的結(jié)果應(yīng)該是 8 ,為什么結(jié)果顯示 nSize 6 呢?

事實(shí)上,很多人對(duì) #pragma pack 的理解是錯(cuò)誤的。
#pragma pack
規(guī)定的對(duì)齊長(zhǎng)度,實(shí)際使用的規(guī)則是:
結(jié)構(gòu),聯(lián)合,或者類(lèi)的數(shù)據(jù)成員,第一個(gè)放在偏移為 0 的地方,以后每個(gè)數(shù)據(jù)成員的對(duì)齊,按照 #pragma pack 指定的數(shù)值和這個(gè)數(shù)據(jù)成員自身長(zhǎng)度中, 比較小 的那個(gè)進(jìn)行。
也就是說(shuō),當(dāng) #pragma pack 的值等于或超過(guò)所有數(shù)據(jù)成員長(zhǎng)度的時(shí)候,這個(gè)值的大小將不產(chǎn)生任何效果。
結(jié)構(gòu)整體 的對(duì)齊,則按照結(jié)構(gòu)體中最大的數(shù)據(jù)成員 和 #pragma pack 指定值 之間,較小的那個(gè)進(jìn)行。

具體解釋
#pragma pack (4)
class TestB
{
public:
int aa; // 第一個(gè)成員,放在 [0,3] 偏移的位置,
char a; // 第二個(gè)成員,自身長(zhǎng)為 1 #pragma pack (4), 取小值,也就是 1 ,所以這個(gè)成員按一字節(jié)對(duì)齊,放在偏移 [4] 的位置。
short b; // 第三個(gè)成員,自身長(zhǎng) 2 #pragma pack (4) ,取 2 ,按 2 字節(jié)對(duì)齊,所以放在偏移 [6,7] 的位置。
char c; // 第四個(gè),自身長(zhǎng)為 1 ,放在 [8] 的位置。
};
這個(gè)類(lèi)實(shí)際占據(jù)的內(nèi)存空間是 9 字節(jié)
類(lèi)之間的對(duì)齊, 是按照類(lèi)內(nèi)部最大的成員的長(zhǎng)度 ,和 #pragma pack 規(guī)定的值之中 較小的一個(gè)對(duì) 齊的。
所以這個(gè)例子中,類(lèi)之間對(duì)齊的長(zhǎng)度是 min(sizeof(int),4) ,也就是 4
9
按照 4 字節(jié)圓整的結(jié)果是 12 ,所以 sizeof(TestB) 12

起始倍數(shù)曰對(duì)齊,

體內(nèi)對(duì)齊,自身 pra 取小值,

體間對(duì)齊,最大 pra 取小值,

體間上取整


如果
#pragma pack (2)
class TestB
{
public:
int aa; // 第一個(gè)成員,放在 [0,3] 偏移的位置,
char a; // 第二個(gè)成員,自身長(zhǎng)為 1 #pragma pack (4), 取小值,也就是 1 ,所以這個(gè)成員按一字節(jié)對(duì)齊,放在偏移 [4] 的位置。
short b; // 第三個(gè)成員,自身長(zhǎng) 2 #pragma pack (4) ,取 2 ,按 2 字節(jié)對(duì)齊,所以放在偏移 [6,7] 的位置。
char c; // 第四個(gè),自身長(zhǎng)為 1 ,放在 [8] 的位置。
};
//
可以看出,上面的位置完全沒(méi)有變化,只是類(lèi)之間改為按 2 字節(jié)對(duì)齊, 9 2 圓整的結(jié)果是 10
//
所以 sizeof(TestB) 10

最后看原貼:
現(xiàn)在去掉第一個(gè)成員變量為如下代碼:
#pragma pack (4)
class TestC
{
public:
char a;// 第一個(gè)成員,放在 [0] 偏移的位置,
short b;// 第二個(gè)成員,自身長(zhǎng) 2 #pragma pack (4) ,取 2 ,按 2 字節(jié)對(duì)齊,所以放在偏移 [2,3] 的位置。
char c;// 第三個(gè),自身長(zhǎng)為 1 ,放在 [4] 的位置。
};
//
整個(gè)類(lèi)的大小是 5 字節(jié),按照 min(sizeof(short),4) 字節(jié)對(duì)齊,也就是 2 字節(jié)對(duì)齊,結(jié)果是 6
//
所以 sizeof(TestC) 6

對(duì)於位域有如下規(guī)定 :

C99 規(guī)定 int unsigned int bool 可以作為位域類(lèi)型,但編譯器幾乎都對(duì)此作了擴(kuò)展,允許其它類(lèi)型類(lèi)型的存在。使用位域的主要目的是壓縮存儲(chǔ),其大致規(guī)則為:
1)
如果相鄰位域字段的類(lèi)型相同,且其位寬之和小于類(lèi)型的 sizeof 大小,則后面的字段將緊鄰前一個(gè)字段存儲(chǔ),直到不能容納為止;
2)
如果相鄰位域字段的類(lèi)型相同,但其位寬之和大于類(lèi)型的 sizeof 大小,則后面的字段將從新的存儲(chǔ)單元開(kāi)始,其偏移量為其類(lèi)型大小的整數(shù)倍;
3)
如果相鄰的位域字段的類(lèi)型不同,則各編譯器的具體實(shí)現(xiàn)有差異, VC6 采取不壓縮方式, Dev-C++ 采取壓縮方式;
4)
如果位域字段之間穿插著非位域字段,則不進(jìn)行壓縮;
5)
整個(gè)結(jié)構(gòu)體的總大小為最寬基本類(lèi)型成員大小的整數(shù)倍。

還是讓我們來(lái)看看例子。
示例 1
struct BF1
{
char f1 : 3;
char f2 : 4;
char f3 : 5;
};
其內(nèi)存布局為:
|_f1__|__f2__|_|____f3___|____|
|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|
0 3 7 8 1316
位域類(lèi)型為 char ,第 1 個(gè)字節(jié)僅能容納下 f1 f2 ,所以 f2 被壓縮到第 1 個(gè)字節(jié)中,而 f3
能從下一個(gè)字節(jié)開(kāi)始。因此 sizeof(BF1) 的結(jié)果為 2

示例 2
struct BF2
{
char f1 : 3;
short f2 : 4;
char f3 : 5;
};
由于相鄰位域類(lèi)型不同,在 VC6 中其 sizeof 6 ,在 Dev-C++ 中為 2

示例 3
struct BF3
{
char f1 : 3;
char f2;
char f3 : 5;
};
非位域字段穿插在其中,不會(huì)產(chǎn)生壓縮,在 VC6 Dev-C++ 中得到的大小均為 3




Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1331903

轉(zhuǎn)自 :http://rabbitlzx.blogbus.com/logs/2006/03/2094407.html

1 、什么是 sizeof

首先看一下 sizeof msdn 上的定義:

The sizeof keyword gives the amount of storage, in bytes, associated with a variable or a type (including aggregate types). This keyword returns a value of type size_t.

看到 return 這個(gè)字眼,是不是想到了函數(shù)?錯(cuò)了, sizeof 不是一個(gè)函數(shù),你見(jiàn)過(guò)給一個(gè)函數(shù)傳參數(shù),而不加括號(hào)的嗎? sizeof 可以,所以 sizeof 不是函數(shù)。網(wǎng)上有人說(shuō) sizeof 是一元操作符,但是我并不這么認(rèn)為,因?yàn)? sizeof 更像一個(gè)特殊的宏,它是在編譯階段求值的。舉個(gè)例子:

cout<<sizeof(int)<<endl; // 32
位機(jī)上 int 長(zhǎng)度為 4
cout<<sizeof(1==2)<<endl; // ==
操作符返回 bool 類(lèi)型,相當(dāng)于 cout<<sizeof(bool)<<endl;

在編譯階段已經(jīng)被翻譯為:

cout<<4<<endl;
cout<<1<<endl;

這里有個(gè)陷阱,看下面的程序:

int a = 0;
cout<<sizeof(a=3)<<endl;
cout<<a<<endl;

輸出為什么是 4 0 而不是期望中的 4 3 ???就在于 sizeof 在編譯階段處理的特性。由于 sizeof 不能被編譯成機(jī)器碼,所以 sizeof 作用范圍內(nèi),也就是 () 里面的內(nèi)容也不能被編譯,而是被替換成類(lèi)型。 = 操作符返回左操作數(shù)的類(lèi)型,所以 a=3 相當(dāng)于 int ,而代碼也被替換為:

int a = 0;
cout<<4<<endl;
cout<<a<<endl;

所以, sizeof 是不可能支持鏈?zhǔn)奖磉_(dá)式的,這也是和一元操作符不一樣的地方。

結(jié)論:不要把 sizeof 當(dāng)成函數(shù),也不要看作一元操作符,把他當(dāng)成一個(gè)特殊的編譯預(yù)處理。

2 sizeof 的用法

sizeof
有兩種用法:

1 sizeof(object)
也就是對(duì)對(duì)象使用 sizeof ,也可以寫(xiě)成 sizeof object 的形式

2 sizeof(typename)
也就是對(duì)類(lèi)型使用 sizeof ,注意這種情況下寫(xiě)成 sizeof typename 是非法的。下面舉幾個(gè)例子說(shuō)明一下:


int i = 2;
cout<<sizeof(i)<<endl; // sizeof(object)
的用法,合理
cout<<sizeof i<<endl; // sizeof object
的用法,合理
cout<<sizeof 2<<endl; // 2
被解析成 int 類(lèi)型的 object, sizeof object 的用法,合理
cout<<sizeof(2)<<endl; // 2
被解析成 int 類(lèi)型的 object, sizeof(object) 的用法,合理
cout<<sizeof(int)<<endl;// sizeof(typename)
的用法,合理
cout<<sizeof int<<endl; //
錯(cuò)誤!對(duì)于操作符,一定要加 ()

可以看出,加 () 是永遠(yuǎn)正確的選擇。

結(jié)論:不論 sizeof 要對(duì)誰(shuí)取值,最好都加上 ()


3 、數(shù)據(jù)類(lèi)型的 sizeof

1 C++ 固有數(shù)據(jù)類(lèi)型

32
C++ 中的基本數(shù)據(jù)類(lèi)型,也就 char,short int(short),int,long int(long),float,double, long double
大小分別是: 1 2 4 4 4 8, 10

考慮下面的代碼:

cout<<sizeof(unsigned int) == sizeof(int)<<endl; //
相等,輸出 1

unsigned
影響的只是最高位 bit 的意義, 數(shù)據(jù)長(zhǎng)度不會(huì)被改變的

結(jié)論: unsigned 不能影響 sizeof 的取值。

2 )自定義數(shù)據(jù)類(lèi)型

typedef
可以用來(lái)定義 C++ 自定義類(lèi)型。考慮下面的問(wèn)題:

typedef short WORD;
typedef long DWORD;
cout<<(sizeof(short) == sizeof(WORD))<<endl; //
相等,輸出 1
cout<<(sizeof(long) == sizeof(DWORD))<<endl; //
相等,輸出 1

結(jié)論:自定義類(lèi)型的 sizeof 取值等同于它的類(lèi)型原形。

3 )函數(shù)類(lèi)型

考慮下面的問(wèn)題:

int f1(){return 0;};
double f2(){return 0.0;}
void f3(){}

cout<<sizeof(f1())<<endl; // f1()
返回值為 int ,因此被認(rèn)為是 int
cout<<sizeof(f2())<<endl; // f2()
返回值為 double ,因此被認(rèn)為是 double
cout<<sizeof(f3())<<endl; //
錯(cuò)誤! 無(wú)法對(duì) void 類(lèi)型使用 sizeof
cout<<sizeof(f1)<<endl; //
錯(cuò)誤!無(wú)法對(duì)函數(shù)指針使用 sizeof
cout<<sizeof*f2<<endl; // *f2
,和 f2() 等價(jià),因?yàn)榭梢钥醋? object ,所以括號(hào)不是必要的。被認(rèn)為是 double

結(jié)論:對(duì)函數(shù)使用 sizeof ,在編譯階段會(huì)被函數(shù)返回值的類(lèi)型取代。

4
、指針問(wèn)題

考慮下面問(wèn)題:

cout<<sizeof(string*)<<endl; // 4
cout<<sizeof(int*)<<endl; // 4
cout<<sizof(char****)<<endl; // 4

可以看到, 不管是什么類(lèi)型的指針, 大小都是 4 ,因?yàn)橹羔樉褪? 32 位的物理地址。指針存放在 32 位物理地址中

結(jié)論:只要是指針,大小就是 4 。( 64 位機(jī)上要變成 8 也不一定)。

順便唧唧歪歪幾句, C++ 中的指針表示實(shí)際內(nèi)存的地址。和 C 不一樣的是, C++ 中取消了模式之分,也就是不再有 small,middle,big, 取而代之的是統(tǒng)一的 flat flat 模式采用 32 位實(shí)地址尋址,而不再是 c 中的 segment:offset 模式。舉個(gè)例子,假如有一個(gè)指向地址 f000:8888 的指針,如果是 C 類(lèi)型則是 8888(16 , 只存儲(chǔ)位移,省略段 ) far 類(lèi)型的 C 指針是 f0008888(32 位,高位保留段地址,地位保留位移 ),C++ 類(lèi)型的指針是 f8888(32 位,相當(dāng)于段地址 *16 + 位移,但尋址范圍要更大 )

5
、數(shù)組問(wèn)題

考慮下面問(wèn)題:

char a[] = "abcdef";
int b[20] = {3, 4};
char c[2][3] = {"aa", "bb"};


cout<<sizeof(a)<<endl; // 7
cout<<sizeof(b)<<endl; // 80
cout<<sizeof(c)<<endl; // 6


數(shù)組 a 的大小在定義時(shí)未指定,編譯時(shí)給它分配的空間是按照初始化的值確定的,也就是 7 c 是多維數(shù)組,占用的空間大小是各維數(shù)的乘積,也就是 6 。可以看出, 數(shù)組的大小就是他在編譯時(shí)被分配的空間,也就是各維數(shù)的乘積 * 數(shù)組元素的大小。

結(jié)論:數(shù)組的大小是各維數(shù)的乘積 * 數(shù)組元素的大小。

這里有一個(gè)陷阱:

int *d = new int[10];

cout<<sizeof(d)<<endl; // 4

d
是我們常說(shuō)的動(dòng)態(tài)數(shù)組,但是他實(shí)質(zhì)上還是一個(gè)指針,所以 sizeof(d) 的值是 4

再考慮下面的問(wèn)題:

double* (*a)[3][6];

cout<<sizeof(a)<<endl; // 4
cout<<sizeof(*a)<<endl; // 72
cout<<sizeof(**a)<<endl; // 24
cout<<sizeof(***a)<<endl; // 4
cout<<sizeof(****a)<<endl; // 8

a
是一個(gè)很奇怪的定義,他表示一個(gè)指向 double*[3][6] 類(lèi)型數(shù)組的指針。既然是指針,所以 sizeof(a) 就是 4

既然 a 是執(zhí)行 double*[3][6] 類(lèi)型的指針, *a 就表示一個(gè) double*[3][6] 的多維數(shù)組類(lèi)型,因此 sizeof(*a)=3*6*sizeof(double*)=72 。同樣的, **a 表示一個(gè) double*[6] 類(lèi)型的數(shù)組,所以 sizeof(**a)=6*sizeof(double*)=24 ***a 就表示其中的一個(gè)元素,也就是 double* 了,所以 sizeof(***a)=4 。至于 ****a ,就是一個(gè) double 了,所以 sizeof(****a)=sizeof(double)=8


6
、向函數(shù)傳遞數(shù)組的問(wèn)題

考慮下面的問(wèn)題:
#include <iostream>
using namespace std;

int Sum(int i[])
{
int sumofi = 0;
for (int j = 0; j < sizeof(i)/sizeof(int); j++) //
實(shí)際上, sizeof(i) = 4
{
sumofi += i[j];
}
return sumofi;
}

int main()
{
int allAges[6] = {21, 22, 22, 19, 34, 12};
cout<<Sum(allAges)<<endl;
system("pause");
return 0;
}

Sum
的本意是用 sizeof 得到數(shù)組的大小,然后求和。但是實(shí)際上,傳入自函數(shù) Sum 的,只是一個(gè) int 類(lèi)型的指針,所以 sizeof(i)=4 ,而不是 24 ,所以會(huì)產(chǎn)生錯(cuò)誤的結(jié)果。解決這個(gè)問(wèn)題的方法使是用指針或者引用。

使用指針的情況:
int Sum(int (*i)[6])
{
int sumofi = 0;
for (int j = 0; j < sizeof(*i)/sizeof(int); j++) //sizeof(*i) = 24
{
sumofi += (*i)[j];
}
return sumofi;
}

int main()
{
int allAges[] = {21, 22, 22, 19, 34, 12};
cout<<Sum(&allAges)<<endl;
system("pause");
return 0;
}
在這個(gè) Sum 里, i 是一個(gè)指向 i[6] 類(lèi)型的指針,注意,這里不能用 int Sum(int (*i)[]) 聲明函數(shù),而是 必須指明要傳入的數(shù)組的大小, 不然 sizeof(*i) 無(wú)法計(jì)算。但是在這種情況下,再通過(guò) sizeof 來(lái)計(jì)算數(shù)組大小已經(jīng)沒(méi)有意義了,因?yàn)榇藭r(shí)大小是指定為 6 的。
使用引用的情況和指針相似:

int Sum(int (&i)[6])
{
int sumofi = 0;
for (int j = 0; j < sizeof(i)/sizeof(int); j++)
{
sumofi += i[j];
}
return sumofi;
}

int main()
{
int allAges[] = {21, 22, 22, 19, 34, 12};
cout<<Sum(allAges)<<endl;
system("pause");
return 0;
}
這種情況下 sizeof 的計(jì)算同樣無(wú)意義,所以用數(shù)組做參數(shù),而且需要遍歷的時(shí)候,函數(shù)應(yīng)該有一個(gè)參數(shù)來(lái)說(shuō)明數(shù)組的大小,而數(shù)組的大小在數(shù)組定義的作用域內(nèi)通過(guò) sizeof 求值。因此上面的函數(shù)正確形式應(yīng)該是:
#include <iostream>
using namespace std;

int Sum(int *i, unsigned int n)
{
int sumofi = 0;
for (int j = 0; j < n; j++)
{
sumofi += i[j];
}
return sumofi;
}

int main()
{
int allAges[] = {21, 22, 22, 19, 34, 12};
cout<<Sum(i, sizeof(allAges)/sizeof(int))<<endl;
system("pause");
return 0;
}

7
、字符串的 sizeof strlen

考慮下面的問(wèn)題:

char a[] = "abcdef";
char b[20] = "abcdef";
string s = "abcdef";

cout<<strlen(a)<<endl; // 6
,字符串長(zhǎng)度
cout<<sizeof(a)<<endl; // 7
,字符串容量
cout<<strlen(b)<<endl; // 6
,字符串長(zhǎng)度
cout<<strlen(b)<<endl; // 20
,字符串容量
cout<<sizeof(s)<<endl; // 12,
這里不代表字符串的長(zhǎng)度,而是 string 類(lèi)的大小
cout<<strlen(s)<<endl; //
錯(cuò)誤! s 不是一個(gè)字符指針。

a[1] = '';
cout<<strlen(a)<<endl; // 1
cout<<sizeof(a)<<endl; // 7
sizeof 是恒定的 因空間已開(kāi)辟


strlen
是尋找從指定地址開(kāi)始,到出現(xiàn)的第一個(gè) 0 之間的字符個(gè)數(shù),他是在運(yùn)行階段執(zhí)行的,而 sizeof 是得到數(shù)據(jù)的大小,在這里是得到字符串的容量。 所以對(duì)同一個(gè)對(duì)象而言, sizeof 的值是恒定的。 string C++ 類(lèi)型的字符串,他是一個(gè)類(lèi),所以 sizeof(s) 表示的并不是字符串的長(zhǎng)度,而是類(lèi) string 的大小。 strlen(s) 根本就是錯(cuò)誤的,因?yàn)? strlen 的參數(shù)是一個(gè)字符指針,如果想用 strlen 得到 s 字符串的長(zhǎng)度,應(yīng)該使用 sizeof(s.c_str()) ,因?yàn)? string 的成員函數(shù) c_str() 返回的是字符串的首地址。實(shí)際上, string 類(lèi)提供了自己的成員函數(shù)來(lái)得到字符串的容量和長(zhǎng)度,分別是 Capacity() Length() string 封裝了常用了字符串操作,所以在 C++ 開(kāi)發(fā)過(guò)程中,最好使用 string 代替 C 類(lèi)型的字符串。


8
、從 union sizeof 問(wèn)題看 cpu 的對(duì)界

考慮下面問(wèn)題:(默認(rèn)對(duì)齊方式)

union u
{
double a;
int b;
};

union u2
{
char a[13];
int b;
};

union u3
{
char a[13];
char b;
};

cout<<sizeof(u)<<endl; // 8
cout<<sizeof(u2)<<endl; // 16
cout<<sizeof(u3)<<endl; // 13

都知道 union 的大小取決于它所有的成員中,占用空間最大的一個(gè)成員的大小。所以對(duì)于 u 來(lái)說(shuō),大小就是最大的 double 類(lèi)型成員 a 了,所以 sizeof(u)=sizeof(double)=8 。但是對(duì)于 u2 u3 ,最大的空間都是 char[13] 類(lèi)型的數(shù)組,為什么 u3 的大小是 13 ,而 u2 16 呢?關(guān)鍵在于 u2 中的成員 int b 。由于 int 類(lèi)型成員的存在,使 u2 的對(duì)齊方式變成 4 ,也就是說(shuō), u2 的大小必須在 4 的對(duì)界上 ( 4 的倍數(shù) ) ,所以占用的空間變成了 16 (最接近 13 的對(duì)界)。

結(jié)論:復(fù)合數(shù)據(jù)類(lèi)型,如 union struct class 的對(duì)齊方式為成員中對(duì)齊方式 最大的成員 的對(duì)齊方式。

順便提一下 CPU 對(duì)界問(wèn)題, 32 C++ 采用 8 位對(duì)界來(lái)提高運(yùn)行速度,所以編譯器會(huì)盡量把數(shù)據(jù)放在它的對(duì)界上以提高內(nèi)存命中率。對(duì)界是可以更改的,使用 #pragma pack(x) 宏可以改變編譯器的對(duì)界方式, 默認(rèn)是 8 C++ 固有類(lèi)型的對(duì)界取 編譯器對(duì)界方式與自身大小中較小的一個(gè) 。例如,指定編譯器按 2 對(duì)界, int 類(lèi)型的大小是 4 ,則 int 的對(duì)界為 2 4 中較小的 2 。在默認(rèn)的對(duì)界方式下,因?yàn)閹缀跛械臄?shù)據(jù)類(lèi)型都不大于默認(rèn)的對(duì)界方式 8 (除了 long double ),所以所有的固有類(lèi)型的對(duì)界方式可以認(rèn)為就是類(lèi)型自身的大小。更改一下上面的程序:

#pragma pack(2)
union u2
{
char a[13];
int b;
};

union u3
{
char a[13];
char b;
};
#pragma pack(8)

cout<<sizeof(u2)<<endl; // 14
cout<<sizeof(u3)<<endl; // 13

由于手動(dòng)更改對(duì)界方式為 2 ,所以 int 的對(duì)界也變成了 2 u2 的對(duì)界取成員中最大的對(duì)界 ,也是 2 了,所以此時(shí) sizeof(u2)=14

結(jié)論: C++ 固有類(lèi)型的對(duì)界取編譯器對(duì)界方式與自身大小中較小的一個(gè)。

9 struct sizeof 問(wèn)題

因?yàn)閷?duì)齊問(wèn)題使結(jié)構(gòu)體的 sizeof 變得比較復(fù)雜,

看下面的例子: ( 默認(rèn)對(duì)齊方式下 )

struct s1{

char a;

double b;

int c;

char d;

};

struct s2{

char a;

char b;

int c;

double d;

};

cout<<sizeof(s1)<<endl; // 24

cout<<sizeof(s2)<<endl; // 16

同樣是兩個(gè) char 類(lèi)型,一個(gè) int 類(lèi)型,一個(gè) double 類(lèi)型,但是

因?yàn)閷?duì)界問(wèn)題,導(dǎo)致他們的大小不同。計(jì)算結(jié)構(gòu)體大小可以采用

元素?cái)[放法,我舉例子說(shuō)明一下:首先, CPU 判斷結(jié)構(gòu)體的對(duì)界,

根據(jù)上一節(jié)的結(jié)論, s1 s2 的對(duì)界都取最大的元素類(lèi)型,也就是

double 類(lèi)型的對(duì)界 8 。然后開(kāi)始擺放每個(gè)元素。

對(duì)于 s1 ,首先把 a 放到 8 的對(duì)界,假定是 0 ,此時(shí)下一個(gè)空閑的地址

1 ,但是下一個(gè)元素 b double 類(lèi)型,要放到 8 的對(duì)界上,離 1

最接近的地址是 8 了,所以 b 被放在了 8 ,此時(shí)下一個(gè)空閑地址變成

16 ,下一個(gè)元素 c 的對(duì)界是 4 16 可以滿(mǎn)足,所以 c 放在了 16

此時(shí)下一個(gè)空閑地址變成了 20 ,下一個(gè)元素 d 需要對(duì)界 1 ,也正好

落在對(duì)界上,所以 d 放在了 20 ,結(jié)構(gòu)體在地址 21 處結(jié)束。由于 s1

大小需要是 8 的倍數(shù) ,所以 21-23 的空間被保留, s1 的大小變成

24

對(duì)于 s2 ,首先把 a 放到 8 的對(duì)界,假定是 0 ,此時(shí)下一個(gè)空閑地址

1 ,下一個(gè)元素的對(duì)界也是 1 ,所以 b 擺放在 1 ,下一個(gè)空閑地址

變成了 2 ;下一個(gè)元素 c 的對(duì)界是 4 ,所以取離 2 最近的地址 4 擺放 c( 4 個(gè)字節(jié)作一個(gè)單位,第一個(gè)單位已被占用 )

下一個(gè)空閑地址變成了 8 ,下一個(gè)元素 d 的對(duì)界是 8 ,所以 d 擺放在 8

所有元素?cái)[放完畢,結(jié)構(gòu)體在 15 處結(jié)束,占用總空間為 16 ,正好

8 的倍數(shù)。

這里有個(gè)陷阱,對(duì)于結(jié)構(gòu)體中的結(jié)構(gòu)體成員,不要認(rèn)為它的

對(duì)齊方式就是他的大小,看下面的例子:

struct s1{

char a[8];

};

struct s2{

double d;

};

struct s3{

s1 s;

char a;

};

struct s4{

s2 s;

char a;

};

cout<<sizeof(s1)<<endl; // 8

cout<<sizeof(s2)<<endl; // 8

cout<<sizeof(s3)<<endl; // 9

cout<<sizeof(s4)<<endl; // 16;

s1 s2 大小雖然都是 8 ,但是 s1 的對(duì)齊方式是 1 s2 8 double ),

所以在 s3 s4 中才有這樣的差異。所以,在自己定義結(jié)構(gòu)體的時(shí)候,如果空間緊張的話,最好考慮

對(duì)齊因素來(lái)排列結(jié)構(gòu)體里的元素。

10 、不要讓 double 干擾你的位域

在結(jié)構(gòu)體和類(lèi)中,可以使用位域來(lái)規(guī)定某個(gè)成員所能占用的空間,

所以 使用位域能在一定程度上節(jié)省結(jié)構(gòu)體占用的空間

不過(guò)考慮下面的代碼:

struct s1{

int i: 8;

int j: 4;

double b;

int a:3;

};

struct s2{

int i;

int j;

double b;

int a;

};

struct s3{

int i;

int j;

int a;

double b;

};

struct s4{

int i: 8;

int j: 4;

int a:3;

double b;

};

cout<<sizeof(s1)<<endl; // 24

cout<<sizeof(s2)<<endl; // 24

cout<<sizeof(s3)<<endl; // 24

cout<<sizeof(s4)<<endl; // 16

可以看到,有 double 存在會(huì)干涉到位域( sizeof 的算法參考上

一節(jié)),所以使用位域的的時(shí)候,最好把 float 類(lèi)型和 double

類(lèi)型放在程序的 開(kāi)始或者最后

------------------------------------------------------------

------------------------------------------------------------

sizeof 在求結(jié)構(gòu)大小時(shí)的使用及 sizeof 主要用法
Tag:
program

本文主要包括二個(gè)部分,第一部分重點(diǎn)介紹在 VC 中,怎么樣采用 sizeof 來(lái)求結(jié)構(gòu)的大小,以及容易出現(xiàn)的問(wèn)題,并給出解決問(wèn)題的方法,第二部分總結(jié)出 VC sizeof 的主要用法。

1 sizeof 應(yīng)用在結(jié)構(gòu)上的情況

請(qǐng)看下面的結(jié)構(gòu):

struct MyStruct

{

double dda1;

char dda;

int type

};


對(duì)結(jié)構(gòu) MyStruct 采用 sizeof 會(huì)出現(xiàn)什么結(jié)果呢? sizeof(MyStruct) 為多少呢?也許你會(huì)這樣求:

sizeof(MyStruct)=sizeof(double)+sizeof(char)+sizeof(int)=13

但是當(dāng)在 VC 中測(cè)試上面結(jié)構(gòu)的大小時(shí),你會(huì)發(fā)現(xiàn) sizeof(MyStruct) 16 。你知道為什么在 VC 中會(huì)得出這樣一個(gè)結(jié)果嗎?

其實(shí),這是 VC 對(duì)變量存儲(chǔ)的一個(gè)特殊處理。 為了提高 CPU 的存儲(chǔ)速度, VC 對(duì)一些變量的起始地址做了 對(duì)齊 處理。 在默認(rèn)情況下, VC 規(guī)定各成員變量存放的起始地址相對(duì)于結(jié)構(gòu)的起始地址的偏移量必須為該變量的類(lèi)型所占用的字節(jié)數(shù)的倍數(shù)。下面列出常用類(lèi)型的對(duì)齊方式 (vc6.0,32 位系統(tǒng) )

類(lèi)型
對(duì)齊方式(變量存放的起始地址相對(duì)于結(jié)構(gòu)的起始地址的偏移量)

Char
偏移量必須為 sizeof(char) 1 的倍數(shù)

int
偏移量必須為 sizeof(int) 4 的倍數(shù)

float
偏移量必須為 sizeof(float) 4 的倍數(shù)

double
偏移量必須為 sizeof(double) 8 的倍數(shù)

Short
偏移量必須為 sizeof(short) 2 的倍數(shù)




各成員變量在存放的時(shí)候根據(jù)在結(jié)構(gòu)中出現(xiàn)的順序依次申請(qǐng)空間,同時(shí)按照上面的對(duì)齊方式調(diào)整位置,空缺的字節(jié) VC 會(huì)自動(dòng)填充。同時(shí) VC 為了確保結(jié)構(gòu)的大小為結(jié)構(gòu)的字節(jié)邊界數(shù)(即該結(jié)構(gòu)中占用最大空間的類(lèi)型所占用的字節(jié)數(shù))的倍數(shù),所以在為最后一個(gè)成員變量申請(qǐng)空間后,還會(huì)根據(jù)需要自動(dòng)填充空缺的字節(jié)

下面用前面的例子來(lái)說(shuō)明 VC 到底怎么樣來(lái)存放結(jié)構(gòu)的。

struct MyStruct

{

double dda1;

char dda;

int type

}


為上面的結(jié)構(gòu)分配空間的時(shí)候, VC 根據(jù)成員變量出現(xiàn)的順序和對(duì)齊方式,先為第一個(gè)成員 dda1 分配空間,其起始地址跟結(jié)構(gòu)的起始地址相同(剛好偏移量 0 剛好為 sizeof(double) 的倍數(shù)),該成員變量占用 sizeof(double)=8 個(gè)字節(jié);接下來(lái)為第二個(gè)成員 dda 分配空間,這時(shí)下一個(gè)可以分配的地址對(duì)于結(jié)構(gòu)的起始地址的偏移量為 8 ,是 sizeof(char) 的倍數(shù),所以把 dda 存放在偏移量為 8 的地方滿(mǎn)足對(duì)齊方式,該成員變量占用 sizeof(char)=1 個(gè)字節(jié);接下來(lái)為第三個(gè)成員 type 分配空間,這時(shí)下一個(gè)可以分配的地址對(duì)于結(jié)構(gòu)的起始地址的偏移量為 9 ,不是 sizeof(int)=4 的倍數(shù),為了滿(mǎn)足對(duì)齊方式對(duì)偏移量的約束問(wèn)題, VC 自動(dòng)填充 3 個(gè)字節(jié)(這三個(gè)字節(jié)沒(méi)有放什么東西),這時(shí)下一個(gè)可以分配的地址對(duì)于結(jié)構(gòu)的起始地址的偏移量為 12 ,剛好是 sizeof(int)=4 的倍數(shù),所以把 type 存放在偏移量為 12 的地方,該成員變量占用 sizeof(int)=4 個(gè)字節(jié);這時(shí)整個(gè)結(jié)構(gòu)的成員變量已經(jīng)都分配了空間,總的占用的空間大小為: 8+1+3+4=16 ,剛好為結(jié)構(gòu)的字節(jié)邊界數(shù)(即結(jié)構(gòu)中占用最大空間的類(lèi)型所占用的字節(jié)數(shù) sizeof(double)=8 )的倍數(shù),所以沒(méi)有空缺的字節(jié)需要填充。所以整個(gè)結(jié)構(gòu)的大小為: sizeof(MyStruct)=8+1+3+4=16 ,其中有 3 個(gè)字節(jié)是 VC 自動(dòng)填充的,沒(méi)有放任何有意義的東西。

下面再舉個(gè)例子,交換一下上面的 MyStruct 的成員變量的位置,使它變成下面的情況:

struct MyStruct

{

char dda;

double dda1;

int type

}


這個(gè)結(jié)構(gòu)占用的空間為多大呢?在 VC6.0 環(huán)境下,可以得到 sizeof(MyStruc) 24 。結(jié)合上面提到的分配空間的一些原則,分析下 VC 怎么樣為上面的結(jié)構(gòu)分配空間的。(簡(jiǎn)單說(shuō)明)

struct MyStruct

{

char dda;//
偏移量為 0 ,滿(mǎn)足對(duì)齊方式, dda 占用

分享到:
評(píng)論
wapysun
  • 瀏覽: 4881624 次
  • 性別: Icon_minigender_1
  • 來(lái)自: 杭州
存檔分類(lèi)
最新評(píng)論

sizeof 用法


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號(hào)聯(lián)系: 360901061

您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對(duì)您有幫助就好】

您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長(zhǎng)會(huì)非常 感謝您的哦!!!

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論