最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C++內(nèi)存對(duì)齊的實(shí)現(xiàn)

 更新時(shí)間:2023年02月05日 16:04:03   作者:TABE_  
本文主要介紹了C++內(nèi)存對(duì)齊的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

內(nèi)存對(duì)齊的基本原則:

  • 結(jié)構(gòu)(struct/class)的內(nèi)置類(lèi)型數(shù)據(jù)成員,第一個(gè)數(shù)據(jù)成員放在offset為0的地方,以后每個(gè)數(shù)據(jù)成員的起始位置要從自身大小的整數(shù)倍開(kāi)始存儲(chǔ)(特別注意64位機(jī)器的指針大小為8個(gè)字節(jié))。
  • 如果一個(gè)結(jié)構(gòu)A里有結(jié)構(gòu)體成員B,則結(jié)構(gòu)體B要從其內(nèi)部"最寬基本類(lèi)型成員”的整數(shù)倍地址開(kāi)始存儲(chǔ)(如struct a里存有struct b,b里有char, int, double等元素,那b應(yīng)該從8的整數(shù)倍位置開(kāi)始存儲(chǔ))。
  • 結(jié)構(gòu)體的總大小為結(jié)構(gòu)體的有效對(duì)齊值的整數(shù)倍,結(jié)構(gòu)體的有效對(duì)齊值的確定:
    • 當(dāng)未明確指定時(shí),以結(jié)構(gòu)體或結(jié)構(gòu)體所包含結(jié)構(gòu)體成員中最長(zhǎng)的成員長(zhǎng)度為其有效值。
    • 當(dāng)用#pragma pack(n)指定時(shí),以n和結(jié)構(gòu)體中最長(zhǎng)的成員的長(zhǎng)度中較小者為其值。
    • 當(dāng)用__attribute__ ((packed))指定長(zhǎng)度時(shí),強(qiáng)制按照此值為結(jié)構(gòu)體的有效對(duì)齊值。
    • 不管# pragma pack和__attribute__如何指定,結(jié)構(gòu)體內(nèi)部成員的自對(duì)齊仍然按照其自身的對(duì)齊值。
  • union以結(jié)構(gòu)里面size最大元素為union的size,因?yàn)樵谀骋粫r(shí)刻,union只有一個(gè)成員真正存儲(chǔ)于該地址。

空類(lèi)/靜態(tài)成員

程序 1

class A{
};

int main() {
?? ?cout << sizeof(A) << endl;?? ?// 1
}

對(duì)于一個(gè)什么都沒(méi)有的空類(lèi),實(shí)際并不是空的,因?yàn)橛心J(rèn)的函數(shù),具體可以參考 (待填入網(wǎng)址),大小是 1,這是因?yàn)樾枰幸粋€(gè)地址,C++ 不允許兩個(gè)不同的對(duì)象有相同的地址,所以 C++ 中空的類(lèi)和結(jié)構(gòu)體大小都是 1。

程序 2

class A{
?? ?A(){}
?? ?~A(){}
?? ?void print() { printf("print()\n"); }
?? ?void foo() { printf("print()\n"); }

?? ?static void sprint() { printf("sprint()\n"); }
};

int main() {
?? ?cout << sizeof(A) << endl;?? ?// 1
}

這個(gè)類(lèi)的大小仍然是1,成員函數(shù)、靜態(tài)成員函數(shù)、靜態(tài)成員變量都是不占用類(lèi)的內(nèi)存的,這是因?yàn)檫@些東西都是類(lèi)的,而不是每個(gè)對(duì)象分別存儲(chǔ)。static變量就是存儲(chǔ)在全局靜態(tài)區(qū)。

需要注意的是,子類(lèi)繼承空類(lèi)后,子類(lèi)如果有自己的數(shù)據(jù)成員,而空基類(lèi)的1個(gè)字節(jié)并不會(huì)加到子類(lèi)中去。

程序 3

class Empty {};
struct D : public Empty {
    int a;
};

sizeof(D)為4。

再來(lái)看另一種情況,一個(gè)類(lèi)包含一個(gè)空類(lèi)對(duì)象數(shù)據(jù)成員,則空類(lèi)對(duì)象的大小仍為1。

程序 4

class Empty {};
class HaveAnInt {
    int x;
    Empty e;
}

在大多數(shù)編譯器中,你會(huì)發(fā)現(xiàn) sizeof(HaveAnInt) 輸出為8。這是由于,Empty類(lèi)的大小雖然為1,然而為了內(nèi)存對(duì)齊,編譯器會(huì)為HaveAnInt額外加上一些字節(jié),使得HaveAnInt被放大到足夠又可以存放一個(gè)int。

內(nèi)置類(lèi)型數(shù)據(jù)成員

程序 1

class Data
{
    char c;
    int a;
};
 
cout << sizeof(Data) << endl;

程序 2

class Data
{
    char c;
    double a;
};
 
cout << sizeof(Data) << endl;

顯然程序 1 輸出的結(jié)果為 8,程序 2 輸出的結(jié)果為 16 .

程序 1 最大的數(shù)據(jù)成員是4bytes,1+4=5,補(bǔ)齊為4的倍數(shù),也就是8。而程序 2 為8bytes,1+8=9,補(bǔ)齊為8的倍數(shù),也就是16。

程序 3

class Data
{
    char c;
    int a;
    char d;
};
 
cout << sizeof(Data) << endl;

程序 4

class Data
{
    char c;
    char d;
    int a;
};
 
cout << sizeof(Data) << endl;

程序 3 運(yùn)行結(jié)果為 12,程序 4 運(yùn)行結(jié)果為 8

class中的數(shù)據(jù)成員放入內(nèi)存的時(shí)候,內(nèi)存拿出一個(gè)內(nèi)存塊來(lái),數(shù)據(jù)成員們排隊(duì)一個(gè)一個(gè)往里放,遇到太大的成員時(shí),不是將其劈成兩半能放多少就放多少,而是等下一個(gè)內(nèi)存塊過(guò)來(lái)。這樣的話(huà),就可以理解為什么程序 3 和程序 4 兩段代碼輸出結(jié)果不一樣了,因?yàn)槌绦?3 是
1 + (3) + 4 + 1 + (3) = 12,而程序 4 是1 + 1 + (2) + 4 = 8。括號(hào)中為補(bǔ)齊的bytes。

結(jié)構(gòu)體數(shù)據(jù)成員

在默認(rèn)條件下,內(nèi)存對(duì)齊是以class中最大的那個(gè)基本類(lèi)型為基準(zhǔn)的,如果class中的數(shù)據(jù)成員包含其他class,則遞歸的取其中最大的基本類(lèi)型來(lái)參與比較。

程序 1

class BigData
{
    char array[33];
};
 
class Data
{
    BigData bd;
    int integer;
    double d;
};
 
cout << sizeof(BigData) << "   " << sizeof(Data) << endl;

程序 2

class BigData
{
    char array[33];
};
 
class Data
{
    BigData bd;
    double d;
};
 
cout << sizeof(BigData) << "   " << sizeof(Data) << endl;

程序 1 和程序 2 運(yùn)行結(jié)果均為:33 48

程序 1 和程序 2 中內(nèi)存對(duì)其的基準(zhǔn)均為8字節(jié),BigData的大小均為33。在程序 1 中,BigData接下來(lái)是個(gè)int(4bytes),能夠放下,這時(shí)候內(nèi)存塊還剩3bytes,而接下來(lái)是個(gè)double(8bytes),放不下,所以要等下一個(gè)內(nèi)存快到來(lái)。因此,程序 1 的Data的size = 33 + 4 + (3) + 8 = 48,同理程序 2 應(yīng)該是
33 + (7) + 8 = 48。

程序 3

?class A { ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
?public: ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
? ? ?double len; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
? ? ?char str[33]; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
?}; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
?class B { ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
?public: ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ?A a; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ?int b; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
?};

cout << sizeof(A) << " ?" << sizeof(B) << endl;

以上代碼輸出的結(jié)果為: 48 56
不同于程序 1 和程序 2 ,程序 3 中的class A實(shí)際會(huì)占用41字節(jié),但會(huì)發(fā)生8字節(jié)對(duì)齊,所以大小為48字節(jié)。對(duì)于class B,成員b的起始位置已發(fā)生8字節(jié)對(duì)齊,而class B整體還會(huì)發(fā)生8字節(jié)對(duì)齊,所以最終大小為56。

虛函數(shù)

C++ 的類(lèi)中如果有虛函數(shù),類(lèi)內(nèi)就會(huì)有一個(gè)虛函數(shù)表的指針 _vptr,指向自己的虛函數(shù)表,vptr 一般都是在類(lèi)的最前邊(取決于編譯器的實(shí)現(xiàn))。

class A {
public:
    A(){}
    virtual ~A(){}
    virtual void foo(){}
    virtual void print() {}
};

由于只是存一個(gè)指向虛函數(shù)表的指針,所以不管有多少個(gè)虛函數(shù),都是 4 字節(jié)大小(32位下,任何指針大小都是 4,64位下,任何指針大小都是 8),比如上面這個(gè)類(lèi) A,size 就是 4。

需要注意的是就是,對(duì)于沒(méi)有 override 的虛函數(shù),基類(lèi)和子類(lèi)中 _vptr 指向的虛函數(shù)表中,這個(gè)虛函數(shù)的地址是一樣的,也就是上邊的 foo() 函數(shù),而對(duì)于重寫(xiě)了的或者默認(rèn)重寫(xiě)的析構(gòu)函數(shù)來(lái)說(shuō),_vptr 指向的虛函數(shù)表中,函數(shù)地址是不一樣的(當(dāng)然兩個(gè)類(lèi)的 _vptr 地址也是不一樣的,這是肯定的),這就能窺探到多態(tài)的實(shí)現(xiàn)了。

繼承

不同的編譯器對(duì)繼承后類(lèi)的大小的計(jì)算方式不同,有的是先繼承后對(duì)齊,有的是先對(duì)齊后繼承。

class A
{
? ? int i;
? ? char c1;
}

class B:public A
{
? ? char c2;
}

class C:public B
{
? ? char c3;
}

sizeof(C)結(jié)果是多少呢,gcc和vs給出了不同的結(jié)果,分別是8、16。

  • gcc中:C相當(dāng)于把所有成員i、c1、c2、c3當(dāng)作是在一個(gè)class內(nèi)部,(先繼承后對(duì)齊)
  • vs中:對(duì)于A,對(duì)齊后其大小是8;對(duì)于B,c2加上對(duì)齊后的A的大小是9,對(duì)齊后就是12;對(duì)于C,c3加上對(duì)齊后的B大小是13,再對(duì)齊就是16 (先對(duì)齊后繼承)

內(nèi)存對(duì)齊的意義

  • 效率原因:經(jīng)過(guò)內(nèi)存對(duì)齊之后,CPU的內(nèi)存訪(fǎng)問(wèn)速度大大提升。
  • 平臺(tái)原因(移植原因):不是所有的硬件平臺(tái)都能訪(fǎng)問(wèn)任意地址上的任意數(shù)據(jù),某些硬件平臺(tái)只能在某些地址處取某些特定類(lèi)型的數(shù)據(jù),否則拋出硬件異常。

比較兩個(gè)結(jié)構(gòu)體可以使用memcmp(void*, void*)嗎?

不可以,memcmp函數(shù)是逐個(gè)字節(jié)進(jìn)行比較的,而struct存在內(nèi)存對(duì)齊,內(nèi)存對(duì)齊時(shí)補(bǔ)的字節(jié)內(nèi)容是垃圾值,所以無(wú)法比較。

到此這篇關(guān)于C++內(nèi)存對(duì)齊的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)C++內(nèi)存對(duì)齊內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • c語(yǔ)言float類(lèi)型小數(shù)點(diǎn)后位數(shù)

    c語(yǔ)言float類(lèi)型小數(shù)點(diǎn)后位數(shù)

    在本篇文章里小編給大家整理了關(guān)于c語(yǔ)言float類(lèi)型小數(shù)點(diǎn)后面有幾位的相關(guān)知識(shí)點(diǎn),需要的朋友們可以學(xué)習(xí)下。
    2020-02-02
  • C++?Boost?ProgramOptions超詳細(xì)講解

    C++?Boost?ProgramOptions超詳細(xì)講解

    Boost是為C++語(yǔ)言標(biāo)準(zhǔn)庫(kù)提供擴(kuò)展的一些C++程序庫(kù)的總稱(chēng)。Boost庫(kù)是一個(gè)可移植、提供源代碼的C++庫(kù),作為標(biāo)準(zhǔn)庫(kù)的后備,是C++標(biāo)準(zhǔn)化進(jìn)程的開(kāi)發(fā)引擎之一,是為C++語(yǔ)言標(biāo)準(zhǔn)庫(kù)提供擴(kuò)展的一些C++程序庫(kù)的總稱(chēng)
    2022-11-11
  • C++?socket通信遇到的問(wèn)題及解決方法

    C++?socket通信遇到的問(wèn)題及解決方法

    這篇文章主要介紹了C++?socket通信遇到的問(wèn)題,通過(guò)代碼修改來(lái)解決這個(gè)問(wèn)題,本文結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2023-08-08
  • C++ 中const對(duì)象與const成員函數(shù)的實(shí)例詳解

    C++ 中const對(duì)象與const成員函數(shù)的實(shí)例詳解

    這篇文章主要介紹了C++ 中const對(duì)象與const成員函數(shù)的實(shí)例詳解的相關(guān)資料,希望通過(guò)本文能讓大家徹底掌握該如何使用,需要的朋友可以參考下
    2017-08-08
  • C語(yǔ)言通過(guò)三種方法實(shí)現(xiàn)屬于你的通訊錄

    C語(yǔ)言通過(guò)三種方法實(shí)現(xiàn)屬于你的通訊錄

    本文將實(shí)現(xiàn)一個(gè)通訊錄,來(lái)實(shí)現(xiàn)人員的增刪插改功能。文中通過(guò)三種形式來(lái)實(shí)現(xiàn)用戶(hù)的增刪插改,其實(shí)也就是一點(diǎn)點(diǎn)的優(yōu)化版本,從靜態(tài)的實(shí)現(xiàn),到動(dòng)態(tài)的實(shí)現(xiàn),最后以文件的形式來(lái)完成,請(qǐng)大家和我一起往下看吧
    2022-11-11
  • linux中查詢(xún)dns示例

    linux中查詢(xún)dns示例

    這篇文章主要介紹了linux中查詢(xún)dns示例,需要的朋友可以參考下
    2014-04-04
  • 淺談C++模板元編程

    淺談C++模板元編程

    本篇文章主要介紹了淺談C++模板元編程,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-12-12
  • C++實(shí)現(xiàn)迷宮算法實(shí)例解析

    C++實(shí)現(xiàn)迷宮算法實(shí)例解析

    這篇文章主要介紹了C++實(shí)現(xiàn)迷宮算法實(shí)例解析,是一個(gè)比較經(jīng)典的C++算法,有一定的學(xué)習(xí)與借鑒價(jià)值,需要的朋友可以參考下
    2014-07-07
  • C語(yǔ)言實(shí)現(xiàn)自動(dòng)存取款機(jī)模擬系統(tǒng)

    C語(yǔ)言實(shí)現(xiàn)自動(dòng)存取款機(jī)模擬系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)自動(dòng)存取款機(jī)模擬系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • c++中?isupper()和islower()函數(shù)詳解

    c++中?isupper()和islower()函數(shù)詳解

    在C++中,islower()和isupper()是C++標(biāo)準(zhǔn)庫(kù)中提供的兩個(gè)字符判斷函數(shù),這兩個(gè)函數(shù)用于判斷一個(gè)字符是否為小寫(xiě)字母或大寫(xiě)字母,這篇文章主要介紹了c++?isupper()?islower()的相關(guān)資料,需要的朋友可以參考下
    2024-05-05

最新評(píng)論

金阳县| 会泽县| 连江县| 武功县| 余江县| 修文县| 什邡市| 沙湾县| 浪卡子县| 合山市| 德令哈市| 英吉沙县| 伽师县| 贞丰县| 柘城县| 诸暨市| 阳城县| 武城县| 武宁县| 昌图县| 迭部县| 肇庆市| 尤溪县| 芮城县| 洪湖市| 武强县| 余庆县| 闸北区| 永登县| 灌阳县| 平度市| 井陉县| 沂南县| 石景山区| 岗巴县| 信阳市| 毕节市| 高阳县| 宁乡县| 清涧县| 舟山市|