一般的, 內(nèi)存布局我們是不需要關(guān)心的, 因?yàn)槲覀冎苯油ㄟ^字段或?qū)傩詠碓L問結(jié)構(gòu)體, 但是與非托管庫操作的時(shí)候, 有時(shí)候就需要注意結(jié)構(gòu)體布局了, 只有保證布局一致, 才能保證直接傳結(jié)構(gòu)體指針時(shí), 非托管代碼能正常訪問到成員.
成都網(wǎng)站設(shè)計(jì)、網(wǎng)站制作、外貿(mào)營銷網(wǎng)站建設(shè)介紹好的網(wǎng)站是理念、設(shè)計(jì)和技術(shù)的結(jié)合。創(chuàng)新互聯(lián)建站擁有的網(wǎng)站設(shè)計(jì)理念、多方位的設(shè)計(jì)風(fēng)格、經(jīng)驗(yàn)豐富的設(shè)計(jì)團(tuán)隊(duì)。提供PC端+手機(jī)端網(wǎng)站建設(shè),用營銷思維進(jìn)行網(wǎng)站設(shè)計(jì)、采用先進(jìn)技術(shù)開源代碼、注重用戶體驗(yàn)與SEO基礎(chǔ),將技術(shù)與創(chuàng)意整合到網(wǎng)站之中,以契合客戶的方式做到創(chuàng)意性的視覺化效果。[StructLayout(LayoutKind.Sequential)] // 聲明 StructLayout
struct MyStruct
{}
序列布局 (Sequential)順序布局就是按照你在結(jié)構(gòu)體中聲明成員的順序, 一個(gè)個(gè)將它們放到內(nèi)存中, 不過需要注意的是, 這些成員不是一個(gè)個(gè)緊挨著的, 他們可能存在內(nèi)存對(duì)齊, 不過這個(gè)我們下面會(huì)詳細(xì)講到.
顯式布局 (Explicit)在這種布局中, 你需要指定結(jié)構(gòu)體中每一個(gè)字段在這個(gè)結(jié)構(gòu)體中的偏移量, 例如你有一個(gè)結(jié)構(gòu)體, 它里面有兩個(gè) int, 你希望這兩個(gè) int 之間隔開 2 字節(jié)的大小, 那么只需要為第一個(gè)結(jié)構(gòu)體指定偏移量為 0, 第二個(gè)結(jié)構(gòu)體偏移量為 6 即可.
自動(dòng)布局 (Auto)在這種布局中, 你不應(yīng)該進(jìn)行與非托管的互操作, 因?yàn)闉榱诵阅? 結(jié)構(gòu)體中的成員順序會(huì)被自動(dòng)調(diào)整. 例如下面這個(gè)明顯沒辦法在不調(diào)整順序與不添加間隔的情況下做到內(nèi)存對(duì)齊的結(jié)構(gòu)體, 它的成員順序, 會(huì)被調(diào)整.
[StructLayout(LayoutKind.Auto)]
struct SomeIntegers
{byte AByte;
short AShortInteger;
byte AnotherByte;
// 你實(shí)際得到的可能是 byte, byte, short 這樣的一個(gè)結(jié)構(gòu)體
}
內(nèi)存對(duì)齊當(dāng)你使用序列布局的時(shí)候, 結(jié)構(gòu)體成員會(huì)有內(nèi)存對(duì)齊現(xiàn)象, 而在進(jìn)行內(nèi)存對(duì)齊時(shí), 會(huì)有以下行為:
包就是內(nèi)存對(duì)齊的要求大小, 例如在 Windows 中默認(rèn)是 8 字節(jié)對(duì)齊, 像是一些大于八字節(jié)的數(shù)據(jù), 按照 8 字節(jié)在內(nèi)存中進(jìn)行對(duì)齊即可.
偏移量要求舉個(gè)例子, 如果我們有一個(gè) int(32位), 那么它的內(nèi)存偏移量應(yīng)該是 4, 8, 12 等這些能夠被 4 整除的值, 同理, long(64位) 的偏移量也應(yīng)該是 8, 16, 32 這些.
舉個(gè)例子, 下面這個(gè)結(jié)構(gòu)體中, 成員 B 為了實(shí)現(xiàn)偏移量為 2, 在成員 A 后產(chǎn)生了 1 字節(jié)的空隙.
[StructLayout(LayoutKind.Sequential)]
struct SomeIntegers
{byte A; // 1 byte
// 1 byte
short B; // 2 bytes
}
成員占用大于包舉個(gè)例子, 在使用 8 字節(jié)的包大小時(shí), 且在一個(gè)包內(nèi), 已經(jīng)被使用了 4 字節(jié), 如果你要裝下一個(gè) long(8字節(jié)), 那么顯然這個(gè)包已經(jīng)裝不下這個(gè)字段了, 那么這個(gè)字段會(huì)放到下一個(gè)包.
舉個(gè)例子, 下面這個(gè)結(jié)構(gòu)體中, 成員 B 為了做到 8 字節(jié)的對(duì)齊, 它與第一個(gè)成員之間, 產(chǎn)生了 4 字節(jié)的空隙.
[StructLayout(LayoutKind.Sequential)]
struct SomeIntegers
{int A; // 4 bytes
// 4 bytes
long B; // 8 bytes
}
但是當(dāng)你指定 Pack 為 4 時(shí), 這個(gè) long 則不再要求偏移量能被 8 整除, 而是被 4 整除即可.
[StructLayout(LayoutKind.Sequential, Pack = 4)]
struct SomeIntegers
{int A; // 4 bytes
long B; // 8 bytes (B 與 A 之間的空隙沒有了)
}
因此, 當(dāng)你不希望這個(gè)結(jié)構(gòu)體產(chǎn)生任何空隙, 或者不希望這個(gè)結(jié)構(gòu)體有內(nèi)存對(duì)齊時(shí), 指定 Pack = 1 就可以解決問題. 因?yàn)檫@樣會(huì)導(dǎo)致所有字段的偏移量能被 1 整除即可, 于是他們對(duì)于偏移量, 就沒有了任何要求.
成員尾部留空一個(gè)結(jié)構(gòu)體尾部也會(huì)產(chǎn)生一些空余的, 不被使用的字節(jié), 這個(gè)字節(jié)大小取決于結(jié)構(gòu)體中大的成員大小.
例如我一個(gè)結(jié)構(gòu)體中, 有一個(gè)long
, 有一個(gè)byte
, 大成員大小為 8, 所以結(jié)構(gòu)體的大小一定是 8 的倍數(shù).
[StructLayout(LayoutKind.Sequential)]
struct TwoIntegers // 大小共計(jì) 16 bytes
{long A; // 8 bytes
byte B; // 1 byte
// 7 bytes
}
當(dāng)結(jié)構(gòu)體嵌套例如我一個(gè)結(jié)構(gòu)體中包含另外一個(gè)結(jié)構(gòu)體, 那么此時(shí), 內(nèi)存如何對(duì)齊呢?
例如一個(gè)結(jié)構(gòu)體中, 有一個(gè)int
字段以及一個(gè)byte
字段, 它的大對(duì)其大小是 4, 也就是說, 這個(gè)結(jié)構(gòu)體在作為其他結(jié)構(gòu)體的成員時(shí), 也會(huì)使用 4 作為對(duì)齊大小.
[StructLayout(LayoutKind.Sequential)]
struct SomeIntegers
{public byte A; // 1 byte
// 3 bytes (結(jié)構(gòu)體大對(duì)齊是 4, 所以這里留出了 4 - 1 = 3 個(gè)字節(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)體成員尾部的留空能夠裝下下一個(gè)成員, 它也不會(huì)這樣做. “結(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 (盡管上一個(gè)結(jié)構(gòu)體字段后有留空, 但這段留空不會(huì)被重復(fù)利用)
// 3 bytes (所有成員的大大小是 4, soyi這里留
}
[StructLayout(LayoutKind.Sequential)]
struct TwoIntegers
{int A; // 4 bytes
byte B; // 1 byte
// 3 bytes
}
實(shí)現(xiàn)聯(lián)合體C++ 中有聯(lián)合體這個(gè)東西, 實(shí)現(xiàn)多個(gè)字段共用一些數(shù)據(jù), 在 C# 中, 如果你要實(shí)現(xiàn)這個(gè), 使用顯式布局即可.
舉個(gè)例子, 在下面這個(gè) C++ 定義的結(jié)構(gòu)體中, 存在兩個(gè)字段 A 和 B, 他們共用相同的內(nèi)存區(qū)域.
struct SomeIntegers
{union {int A;
int B;
};
};
在 C# 中實(shí)現(xiàn)這個(gè), 你可以使用:
[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# 進(jìn)行編寫:
[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)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級(jí)服務(wù)器適合批量采購,新人活動(dòng)首月15元起,快前往官網(wǎng)查看詳情吧