[.NET]結(jié)構(gòu)體布局詳解與結(jié)構(gòu)體內(nèi)存對齊具體方式-創(chuàng)新互聯(lián)

內(nèi)存布局

一般的, 內(nèi)存布局我們是不需要關(guān)心的, 因為我們直接通過字段或?qū)傩詠碓L問結(jié)構(gòu)體, 但是與非托管庫操作的時候, 有時候就需要注意結(jié)構(gòu)體布局了, 只有保證布局一致, 才能保證直接傳結(jié)構(gòu)體指針時, 非托管代碼能正常訪問到成員.

成都網(wǎng)站設計、網(wǎng)站制作、外貿(mào)營銷網(wǎng)站建設介紹好的網(wǎng)站是理念、設計和技術(shù)的結(jié)合。創(chuàng)新互聯(lián)建站擁有的網(wǎng)站設計理念、多方位的設計風格、經(jīng)驗豐富的設計團隊。提供PC端+手機端網(wǎng)站建設,用營銷思維進行網(wǎng)站設計、采用先進技術(shù)開源代碼、注重用戶體驗與SEO基礎,將技術(shù)與創(chuàng)意整合到網(wǎng)站之中,以契合客戶的方式做到創(chuàng)意性的視覺化效果。
[StructLayout(LayoutKind.Sequential)]    // 聲明 StructLayout 
struct MyStruct
{}
序列布局 (Sequential)

順序布局就是按照你在結(jié)構(gòu)體中聲明成員的順序, 一個個將它們放到內(nèi)存中, 不過需要注意的是, 這些成員不是一個個緊挨著的, 他們可能存在內(nèi)存對齊, 不過這個我們下面會詳細講到.

顯式布局 (Explicit)

在這種布局中, 你需要指定結(jié)構(gòu)體中每一個字段在這個結(jié)構(gòu)體中的偏移量, 例如你有一個結(jié)構(gòu)體, 它里面有兩個 int, 你希望這兩個 int 之間隔開 2 字節(jié)的大小, 那么只需要為第一個結(jié)構(gòu)體指定偏移量為 0, 第二個結(jié)構(gòu)體偏移量為 6 即可.

自動布局 (Auto)

在這種布局中, 你不應該進行與非托管的互操作, 因為為了性能, 結(jié)構(gòu)體中的成員順序會被自動調(diào)整. 例如下面這個明顯沒辦法在不調(diào)整順序與不添加間隔的情況下做到內(nèi)存對齊的結(jié)構(gòu)體, 它的成員順序, 會被調(diào)整.

[StructLayout(LayoutKind.Auto)]
struct SomeIntegers
{byte AByte;
    short AShortInteger;
    byte AnotherByte;

    // 你實際得到的可能是 byte, byte, short 這樣的一個結(jié)構(gòu)體
}
內(nèi)存對齊

當你使用序列布局的時候, 結(jié)構(gòu)體成員會有內(nèi)存對齊現(xiàn)象, 而在進行內(nèi)存對齊時, 會有以下行為:

  1. 一個成員的內(nèi)存偏移量, 應該能夠被它自身所占大小整除
  2. 如果一個成員占用內(nèi)存大于包(Pack)的大小, 那么不再要求它的偏移量能被它自身大小整除, 而是能夠被包大小整除即可.
什么是包

包就是內(nèi)存對齊的要求大小, 例如在 Windows 中默認是 8 字節(jié)對齊, 像是一些大于八字節(jié)的數(shù)據(jù), 按照 8 字節(jié)在內(nèi)存中進行對齊即可.

偏移量要求

舉個例子, 如果我們有一個 int(32位), 那么它的內(nèi)存偏移量應該是 4, 8, 12 等這些能夠被 4 整除的值, 同理, long(64位) 的偏移量也應該是 8, 16, 32 這些.

舉個例子, 下面這個結(jié)構(gòu)體中, 成員 B 為了實現(xiàn)偏移量為 2, 在成員 A 后產(chǎn)生了 1 字節(jié)的空隙.

[StructLayout(LayoutKind.Sequential)]
struct SomeIntegers
{byte A;     // 1 byte
                // 1 byte
    short B;    // 2 bytes
}
成員占用大于包

舉個例子, 在使用 8 字節(jié)的包大小時, 且在一個包內(nèi), 已經(jīng)被使用了 4 字節(jié), 如果你要裝下一個 long(8字節(jié)), 那么顯然這個包已經(jīng)裝不下這個字段了, 那么這個字段會放到下一個包.

舉個例子, 下面這個結(jié)構(gòu)體中, 成員 B 為了做到 8 字節(jié)的對齊, 它與第一個成員之間, 產(chǎn)生了 4 字節(jié)的空隙.

[StructLayout(LayoutKind.Sequential)]
struct SomeIntegers
{int A;    // 4 bytes
              // 4 bytes
    long B;   // 8 bytes
}

但是當你指定 Pack 為 4 時, 這個 long 則不再要求偏移量能被 8 整除, 而是被 4 整除即可.

[StructLayout(LayoutKind.Sequential, Pack = 4)]
struct SomeIntegers
{int A;    // 4 bytes
    long B;   // 8 bytes (B 與 A 之間的空隙沒有了)
}

因此, 當你不希望這個結(jié)構(gòu)體產(chǎn)生任何空隙, 或者不希望這個結(jié)構(gòu)體有內(nèi)存對齊時, 指定 Pack = 1 就可以解決問題. 因為這樣會導致所有字段的偏移量能被 1 整除即可, 于是他們對于偏移量, 就沒有了任何要求.

成員尾部留空

一個結(jié)構(gòu)體尾部也會產(chǎn)生一些空余的, 不被使用的字節(jié), 這個字節(jié)大小取決于結(jié)構(gòu)體中大的成員大小.

例如我一個結(jié)構(gòu)體中, 有一個long, 有一個byte, 大成員大小為 8, 所以結(jié)構(gòu)體的大小一定是 8 的倍數(shù).

[StructLayout(LayoutKind.Sequential)]
struct TwoIntegers  // 大小共計 16 bytes
{long A;  // 8 bytes
    byte B;  // 1 byte
             // 7 bytes
}
當結(jié)構(gòu)體嵌套

例如我一個結(jié)構(gòu)體中包含另外一個結(jié)構(gòu)體, 那么此時, 內(nèi)存如何對齊呢?

  1. 結(jié)構(gòu)體字段與前一個字段之間會產(chǎn)生的間隙, 取決于結(jié)構(gòu)體中大的對齊大小.
  2. 結(jié)構(gòu)體字段自身所存在的尾部留空內(nèi)存, 仍然會在外層結(jié)構(gòu)體中保留
1. 結(jié)構(gòu)體字段前的間隙

例如一個結(jié)構(gòu)體中, 有一個int字段以及一個byte字段, 它的大對其大小是 4, 也就是說, 這個結(jié)構(gòu)體在作為其他結(jié)構(gòu)體的成員時, 也會使用 4 作為對齊大小.

[StructLayout(LayoutKind.Sequential)]
struct SomeIntegers
{public byte A;              // 1 byte
                                // 3 bytes (結(jié)構(gòu)體大對齊是 4, 所以這里留出了 4 - 1 = 3 個字節(jié))
    public TwoIntegers B;       // 16 bytes
    public byte C;              // 1 byte
                                // 7 bytes
}

[StructLayout(LayoutKind.Sequential)]
struct TwoIntegers
{int A;     // 4 bytes
    byte B;    // 1 
}
2. 結(jié)構(gòu)體尾部留空

即便結(jié)構(gòu)體成員尾部的留空能夠裝下下一個成員, 它也不會這樣做. “結(jié)構(gòu)體自己的內(nèi)存空間完整不可侵犯”

[StructLayout(LayoutKind.Sequential)]
struct SomeIntegers
{public byte A;              // 1 byte
                                // 3 byte
    public TwoIntegers B;       // 8 bytes
    public byte C;              // 1 byte   (盡管上一個結(jié)構(gòu)體字段后有留空, 但這段留空不會被重復利用)
                                // 3 bytes  (所有成員的大大小是 4, soyi這里留
}

[StructLayout(LayoutKind.Sequential)]
struct TwoIntegers
{int A;    // 4 bytes
    byte B;   // 1 byte
              // 3 bytes
}
實現(xiàn)聯(lián)合體

C++ 中有聯(lián)合體這個東西, 實現(xiàn)多個字段共用一些數(shù)據(jù), 在 C# 中, 如果你要實現(xiàn)這個, 使用顯式布局即可.

舉個例子, 在下面這個 C++ 定義的結(jié)構(gòu)體中, 存在兩個字段 A 和 B, 他們共用相同的內(nèi)存區(qū)域.

struct SomeIntegers
{union {int A;
        int B;
    };
};

在 C# 中實現(xiàn)這個, 你可以使用:

[StructLayout(LayoutKind.Explicit)]
struct SomeIntegers
{[FieldOffset(0)]
    int A;

    [FieldOffset(0)]
    int B;
}

或者這樣的 C++ 結(jié)構(gòu)體:

struct SomeIntegers
{union {int A;
        struct {short Head;
            short Tail;
        };
    };
};

可以這樣用 C# 進行編寫:

[StructLayout(LayoutKind.Explicit)]
struct SomeIntegers
{[FieldOffset(0)]
    int A;               // 占 4 字節(jié)

    [FieldOffset(0)]
    short Head;          // 占 2 字節(jié)

    [FieldOffset(2)]
    short Tail;          // 占 2 字節(jié)
}

你是否還在尋找穩(wěn)定的海外服務器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機房具備T級流量清洗系統(tǒng)配攻擊溯源,準確流量調(diào)度確保服務器高可用性,企業(yè)級服務器適合批量采購,新人活動首月15元起,快前往官網(wǎng)查看詳情吧

網(wǎng)頁題目:[.NET]結(jié)構(gòu)體布局詳解與結(jié)構(gòu)體內(nèi)存對齊具體方式-創(chuàng)新互聯(lián)
網(wǎng)站路徑:http://muchs.cn/article26/dpcojg.html

成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供建站公司、外貿(mào)網(wǎng)站建設、Google、企業(yè)網(wǎng)站制作、外貿(mào)建站、云服務器

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

成都做網(wǎng)站