--- tags: C 語言 --- # C 語言: struct ## aligment (對齊) >以下是以 64 位元環境下的型別大小為例。要注意這些型別會根據平台架構而有所不同。 結構體 `(struct)` 對齊的規則可分為兩個部分: 1. 結構體成員的對齊方式: - 根據各成員的對齊要求來對齊,如果沒有對齊則填補 padding byte 2. 整個結構體大小的對齊方式: - 必須是最大型別成員大小的倍數 計算順序是先滿足第一點,然後再計算第二點。 ```c struct foo1 { int a; // 4 bytes int b; // 4 bytes int c; // 4 bytes }; ``` 在 `foo1` 中,結構體成員已對齊,且整個結構體大小也為 `int` 的倍數,因此 sizeof(struct foo1) = 12。 ```c struct foo2 { char a; // 1 bytes int b; // 4 bytes int c; // 4 bytes }; // 加入 padding 後: struct foo2 { char a; // 1 bytes // 3 bytes padding int b; // 4 bytes int c; // 4 bytes }; ``` 在 `foo2` 中,為了讓 b 能夠以 4 個位元組位置對齊,因此在 a 後面加入了 3 個位元組的 padding。成員內對齊後結構體大小也為 `int` 的倍數,因此 sizeof(struct foo2) = 12。 ```c struct foo3 { short int a; // 2 bytes char b; // 1 byte int c; // 4 bytes }; // 加入 padding 後: struct foo3 { short int a; // 2 bytes char b; // 1 byte // 1 byte padding int c; // 4 bytes }; ``` 在 `foo3` 中,了讓 c 能夠以 4 個位元組位置對齊,因此在 a 後面加入了 1 個位元組的 padding。成員內對齊後結構體大小也為 `int` 的倍數,因此 sizeof(struct foo3) = 8。 ```c struct foo4 { char *a; // 8 bytes unsigned int b; // 4 bytes char c; // 1 bytes // 3 bytes padding }; ``` 在 `foo4` 中,成員內部已對齊,但成員大小總和為 13,不是最大成員型別 `char *` 的倍數,因此在結構尾端會在 padding 3個位元,因此 sizeof(struct foo3) = 16。 ```c struct foo5 { char a; // 1 byte int b; // 4 bytes int c; // 4 bytes char *d; // 8 bytes char e[9]; // 9 bytes long f; // 8 bytes }; // 加入 padding 後: struct foo5 { char a; // 1 byte // 3 bytes padding int b; // 4 bytes int c; // 4 bytes // 4 bytes padding char *d; // 8 bytes char e[9]; // 9 bytes // 7 bytes padding long f; // 8 bytes }; ``` 在 `foo5` 中,`char e[9]` 與 `long f` 對齊,因此填充至最接近的 8 位元倍數:16 位元,故有 7 位元的填充,因此 sizeof(struct foo4) = 40。 ```c struct foo6 { union { // 4 bytes char a; int b; }; char *c; // 8 bytes int d; // 4 bytes char e; // 1 byte }; // 加入 padding 後: struct foo6 { union { // 4 bytes char a; int b; }; // 4 bytes padding char *c; // 8 bytes int d; // 4 bytes char e; // 1 byte // 3 padding }; ``` 在 `foo6` 中,union 的對齊方式也是相同的。在 `foo6` 內的 union 大小為 4 個位元,因此與 `char *c` 對齊為 8 個位元。成員的位元總和為 21,需要與 `char *` 的 8 位元倍數對齊,因此 sizeof(struct foo5) = 24。 ```c union foo7 { struct { char a[2]; long b; char c; }; char *d; char e; }; // 加入 padding 後: union foo7 { struct { char a[2]; // 2 bytes // 6 bytes padding long b; // 8 bytes char c; // 1 byte // 7 bytes padding }; char *d; char e; }; ``` 同理,sizeof (union foo7) = 24。 ## bit field 引述 [維基百科](https://zh.wikipedia.org/zh-tw/%E4%BD%8D%E6%AE%B5) 介紹: 位元欄(或稱「位域」,Bit field)為一種資料結構,可以把資料以位元的形式緊湊的儲存,並允許程式設計師對此結構的位元進行操作。這種資料結構的好處: - 可以使資料單元節省儲存空間,當程式需要成千上萬個資料單元時,這種方法就顯得尤為重要。 - 位元欄可以很方便的訪問一個整數值的部分內容從而可以簡化程式原始碼。 下面用一些例子來觀察 `bit field` 的行為。 ```c struct foo1 { int a:4; // 4 bits int b:4; // 4 bits int c:4; // 4 bits int d:4; // 4 bits }; int i = 0xFA; // 11111010; struct foo1 *f1 = (struct foo1 *)&i; // sizeof (struct foo1) = 4 ``` 我們以 GDB 來觀察 ```shell (gdb) p *f1 $1 = {a = -6, b = -1, c = 0, d = 0} (gdb) x/4tb f1 0x7fffffffe22c: 11111010 00000000 00000000 00000000 ``` 這邊可以得到下面結果: <font color=#32AA6A>b</font> <font color=#CC3BCC>a</font> d c <font color=#32AA6A>1111</font> <font color=#CC3BCC>1010</font> 0000 0000 ```c struct foo2 { int a:4; int b:4; int c:4; int d:4; int :0; // zero-length bit-field int e:4; int f:4; }; int i[] = {0xABCD, 0x00EF}; struct foo2 *f2 = (struct foo2 *)&i; ``` 此外,還有一種 `zero-length` `bit-field`,像在 foo2 結構中所示,這會讓從 `e` 開始的成員從另一個記憶體位置開始。 以 GDB 來觀察 ```shell (gdb) p *f2 $1 = {a = -3, b = -4, c = -5, d = -6, e = -1, f = -2} (gdb) x/8tb f2 0x7fffffffe230: 11001101 10101011 00000000 00000000 11101111 00000000 00000000 00000000 ``` <font color=#32AA6A>b</font> <font color=#32AA6A>a</font> <font color=#32AA6A>d</font> <font color=#32AA6A>c</font> <font color=#CC3BCC>f</font> <font color=#CC3BCC>e</font> <font color=#32AA6A>1100</font> <font color=#32AA6A>1101</font> <font color=#32AA6A>1010</font> <font color=#32AA6A>1011</font> <font color=#32AA6A>00000000 00000000</font> <font color=#CC3BCC>1110</font> <font color=#CC3BCC>1111</font> <font color=#CC3BCC>00000000 00000000</font> 另外也可以從 sizeof(struct foo2) 來觀察: - 有 zero-length bit-field, sizeof(struct foo2) = 8 - 沒有 zero-length bit-field, sizeof(struct foo2) = 4
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up