C/C++結(jié)構(gòu)體使用與自定義字節(jié)對齊

文檔聲明:
以下資料均屬于本人在學(xué)習(xí)過程中產(chǎn)出的學(xué)習(xí)筆記,如果錯誤或者遺漏之處,請多多指正。并且該文檔在后期會隨著學(xué)習(xí)的深入不斷補(bǔ)充完善。


資料僅供學(xué)習(xí)交流使用。
作者:Aliven888

1、簡述

? 結(jié)構(gòu)體(struct)是一種集合,它里面包含了多個(gè)變量或數(shù)組,它們的類型可以相同,也可以不同,每個(gè)這樣的變量或數(shù)組都稱為結(jié)構(gòu)體的成員(Member)。

2、定義格式

常用格式:

struct MyStructName
{
    參數(shù)類型  參數(shù);   //例如:int a;
    ...    //參數(shù)可有多個(gè),而且類型不同
};

**直接定義一個(gè)結(jié)構(gòu)體變量(全局可以用):

struct MyStructName
{
    參數(shù)類型  參數(shù);   //例如:int a;
    ...    //參數(shù)可有多個(gè),而且類型不同
}stu;  //該結(jié)構(gòu)體變量 stu 可以直接使用

**定義唯一結(jié)構(gòu)體變量(全局可以用):

struct MyStructName
{
    參數(shù)類型  參數(shù);   //例如:int a;
    ...    //參數(shù)可有多個(gè),而且類型不同
}stu;  //該結(jié)構(gòu)體變量 stu 是唯一的

為結(jié)構(gòu)體定義一個(gè)別名:

typedef struct MyStructName
{
    參數(shù)類型  參數(shù);   //例如:int a;
    ...    //參數(shù)可有多個(gè),而且類型不同
}stu_MyStuName;  //可以使用stu_MyStuName定義結(jié)構(gòu)體變量

eg : stu_MyStuName st;  //使用別名定義結(jié)構(gòu)體對象 st

3、結(jié)構(gòu)體的使用

首先我們定義一個(gè)結(jié)構(gòu)體:

struct MyStruct  //因?yàn)槭桥e例,定義的比較簡單
{
    int a;
};

定義結(jié)構(gòu)體對象與訪問參數(shù):

//C 語言中的定義方式
struct MyStruct obj;  //或者指針形式:struct MyStruct *obj; 

//C++中支持的定義方式
MyStruct obj;  //或者指針形式:MyStruct *obj; 

//參數(shù)訪問           指針形式訪問
obj.a = 0x01;   // obj->a = 0x01;

4、結(jié)構(gòu)體內(nèi)存計(jì)算

struct MyStruct
{
    byte bValue;
    WORD wValue;
    int iValue;
    double dbValue;

    MyStruct()
    {
        bValue = 0x00;
        wValue = 0x00;
        iValue = 0x00;
        dbValue = 0.0;
    }
}stu;

void test()
{
    cout << "stu len = " << sizeof(stu) << endl;
}
運(yùn)行結(jié)果

? 我們運(yùn)行上面的代碼發(fā)現(xiàn),結(jié)構(gòu)體的長度并不是我們想象的 1 + 2 + 4 + 8 = 15,而是 16,其實(shí)這就是由于字節(jié)對齊導(dǎo)致的。

計(jì)算機(jī)實(shí)際在計(jì)算該結(jié)構(gòu)體長度的流程是:

1、首先計(jì)算 byte bValue 占 一個(gè) 字節(jié)。 //len = 1
2、計(jì)算 WORD wValue 時(shí),發(fā)現(xiàn) len 和 2 不是整數(shù)倍關(guān)系,所以對 a 進(jìn)行了補(bǔ)齊,此時(shí) a 占用兩個(gè)字節(jié)。 //len = 2 + 2 = 4
3、計(jì)算 int iValue 時(shí),len 剛好和 4 是整數(shù)倍關(guān)系 // len = 4 + 4 = 8
4、計(jì)算 double dbValue 時(shí),len 剛好和 8 是整數(shù)倍關(guān)系 // len = 8 + 8 = 16。

5、自定義字節(jié)對齊

? 通過第四小節(jié)我們發(fā)現(xiàn),計(jì)算機(jī)系統(tǒng)會對結(jié)構(gòu)進(jìn)行自動字節(jié)對齊,到時(shí)我們得到的結(jié)構(gòu)體長度并不會是我們期望中的長度。那么有什么方法可以滿足我們得到期望中的長度呢? 其實(shí)很簡單,我們可以通過自定義字節(jié)對齊的方式,讓最終得到的結(jié)構(gòu)體長度等于我們的期望值。

這里我們可以通過使用的下面的方法來實(shí)現(xiàn):

#pragma pack(push):
?英文單詞push是“壓入”的意思。編譯器編譯到此處時(shí)將保存對齊狀態(tài)(保存的是push指令之前的對齊狀態(tài))。

#pragma pack(n):
?這樣就可以知道,當(dāng)我們想要一個(gè)結(jié)構(gòu)體按照4字節(jié)對齊時(shí),可以使用#pragma pack(4) ,如果又想使用默認(rèn)對齊方式時(shí),可以使用#pragma pack() 。

#pragma pack(pop):
?英文單詞pop是”彈出“的意思。編譯器編譯到此處時(shí)將恢復(fù)push指令前保存的對齊狀態(tài)(請?jiān)谑褂迷擃A(yù)處理命令之前使用#pragma pack(push))。

注意事項(xiàng):
?push和pop是一對應(yīng)該同時(shí)出現(xiàn)的名詞,只有pop沒有push不起作用,只有push沒有pop可以保持之前對齊狀態(tài)(但是這樣就沒有使用push的必要了)。

使用格式:

#pragma pack(push)
#pragma pack(4)
    
struct MyStruct
{
    ....
};

#pragma pack(pop)

?這樣在push和pop之間的結(jié)構(gòu)體就可以按照pack指定的字節(jié)(這里是4字節(jié)對齊方式),而pop之后的結(jié)構(gòu)體按照#pragma pack(push) 前對齊方式。

#pragma pack(push)  
#pragma   pack(1) 
struct MyStruct
{
    byte bValue;
    WORD wValue;
    int iValue;
    double dbValue;

    MyStruct()
    {
        bValue = 0x00;
        wValue = 0x00;
        iValue = 0x00;
        dbValue = 0.0;
    }
}stu;
#pragma   pack(pop)
void test()
{
    cout << "stu len = " << sizeof(stu) << endl;
}

此時(shí),我們在運(yùn)行上面的代碼發(fā)現(xiàn),結(jié)構(gòu)體的長度就是 1 + 2 + 4 + 8 = 15了。


運(yùn)行結(jié)果
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容