仔细讨论 C/C++ 字节对齐问题⭐⭐
原文:https://www.cnblogs.com/AlexMiller/p/5509609.html
字節對齊的原因
????為了提高 CPU 的存儲速度,編譯器會對 struct 和 union的存儲進行優化,即進行字節對齊。
對齊方式
????對于 struct 或 union 中的 struct 或者 union 來說,它們的字節對齊標準就是它的所有成員中字節數最大的數據的字節數。
一般情況下 C/C++ 的變量所占用的字節數
??????? char:??? 1字節;
?? ???? short:?? 2字節;
?? ???? int:?????? 4字節;
?? ???? long:??? 4字節;
?? ???? long long: 8字節;
?? ???? float:??? 4字節;
?? ???? double: 8字節;
?? ???? bool:??? 1字節;
*struct 中字節對齊需要滿足的條件:對齊兩原則
????1、某個變量存放的起始位置相對于結構的起始位置的偏移量是該變量字節數的整數倍;
????2、結構所占用的總字節數是結構種字節數最長的變量的字節數的整數倍。
????例:
1 struct Struct 2 { 3 double d1; 4 char d2; 5 int d3; 6 }a;sizeof(a) = 8 + 1 + 3 + 4 = 16。其中補上的 3 個字節是為了讓 int 型數據的起始位置相對于結構起始位置的偏移量為 4 的整數倍。
1 struct Struct 2 { 3 char d1; 4 double d2; 5 int d3; 6 }b;sizeof(b) = 1 + 7 + 8 + 4 = 20。 20 / 8 = 2 …… 4,所以需要再補上 4 個字節,使之成為 8 的 整數倍
*union 中字節對齊需要滿足的兩個條件:對齊兩原則
????1、unoin 的大小必須足夠容納最寬的成員;
????2、union 的大小需要能夠被其所包含的基礎成員類型的大小所整除。
?
字節對齊的另一種方式
????VC提供了 #pragma pack(n) 用來自定義字節對齊方式
????有一下兩種情況:
????????1、n 大于變量的字節數:偏移量只滿足默認的字節對齊方式;
????????2、n 小于變量所占的字節數:偏移量是 n 的整數倍,不使用默認的字節對齊方式。
????例:
1 #pragma pack(push) // 保持對齊狀態2 #pragma pack(4) // 設定為 4 字節對齊3 struct test4 {5 char m1;6 double m2;7 int m3;8 }a;9 #pragma pack(pop) // 恢復對齊狀態 10 sizeof(a) = 1 + 3 + 8 + 4 = 16 // 其中補上三位是因為 n 小于 8,所以 m2 的起始位置相對于結構起始位置的偏移量是 n,即為 4. 11 12 13 #pragma pack(8) 14 struct S1 15 { 16 char a; 17 long b; 18 }; 19 struct S2 20 { 21 char c; 22 struct S1 d; 23 long long e; 24 }; 25 #pragma pack() 26 27 sizeof(S1) = 1 + 3 + 4 = 8 28 sizeof(S2) = 1 + 3 + 8 + 4 + 8 = 24。// 其中加上的 4 是因為變量 e 的字節數是 8 ,其相對與起始位置的偏移量必須是 8 的倍數。????
字節對齊問題的討論到上邊已經結束了。下面再加上我碰到的兩道題目作為實例:
1、典 ???
1 #include <stdio.h>2 union3 {4 char x[5];5 int i;6 }a;7 8 int main()9 { 10 a.x[0] = 10; 11 a.x[1] = 1; 12 printf("%d\n", a.i); 13 printf("%d\n", sizeof(a)); 14 return 0; 15 }?
輸出為 266 8
解析:
對 union 分配內存涉及字節對齊問題,在上方已有詳細描述,在此只簡單解釋一番。union 分配的內存必須是 union 中所有基本數據類型的倍數。
在此題中即為 1 和 4 的倍數,又 char x[5] 占用 5 個字節,故 union 分配的內存大小應為 8 個字節。
windows 系統中高字節在后,低字節在前。而 char x[5] 只有前兩個元素有值,即兩個值只占 2 個字節,也即 union 中的 int 型數據中只有低兩位上有值。
即 i 的二進制表示為:
????00000000 00000000 00000001 00001010
????即: 2^1 + 2^3 + 2^8 = 266
也相當于十六進制 0x010A, 即: 10 * 16^0 + 1 * 16^2 = 266
題2
struct T { char a; int *d; int b; int c:16; double e; }; T *p; 在64位系統以及64位編譯器下,以下描述正確的是正確答案: C ??你的答案: C?(正確)
A:sizeof(p) == 24 (8) B:sizeof(*p) == 24 (32) C:sizeof(p->a) == 1 D:sizeof(p->e) == 4 (8)a占一個字節(注:地址為[0]),d作為64位指針占8個字節(注1:32位占四個字節,p也一樣)(注2:根據上面的準則2,d的偏移量要為8的整數倍,所以d的地址為[8]-[15],而非[1]-[8],下同),b占了4個字節(注:地址為[16][19]),c指定為16為,占了兩個字節(注:地址為[20,21]),e占8個字節,(同d的分析一樣,e的地址應該為[24][31]),所以A的答案應該是8,B的答案是32,C正確,D的答案為8。
這里補充一下進制轉換問題,也是我一并搜集來的:
進制互相轉換
| 十進制 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
| 十六進制 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F |
| 二進制 | 0000 | 0001 | 0010 | 0011 | 0100 | 0101 | 0110 | 0111 | 1000 | 1001 | 1010 | 1011 | 1100 | 1101 | 1110 | 1111 |
十六進制數字轉換十進制數字: ?? ??? ?
0x2AF5轉換十進制:?? ??? ??? ?
5 * 16^0 = 5?? ??? ??? ?
F * 16^1 = 240?? ??? ??? ?
A * 16^2 = 2560?? ??? ??? ?
2 * 16^3 = 8192?? ??? ??? ?
---------------?? ??? ??? ?
5 + 240 + 2560 + 8192 = 10997?? ?
十進制數字轉換十六進制數字:?? ??? ?
2500轉換十六進制:?? ??? ??? ?
2500 / 16 = 156 …… 4?? ??? ??? ?
156 / 16 = 9 …… 12(C)?? ??? ??? ?
9 / 16 = 0 …… 9?? ??? ??? ?
----------------------?? ??? ??? ?
得到4C9,倒轉9C4,即2500的十六進制表示是: 0x9C4?? ?
二進制數字轉換十六進制數字:?? ??? ?
101110011011.1001?? ??? ?
采取四合一法,即以二進制的小數點為分界點,向左(或向右)每四位取一位。?? ??? ?
組分好以后,對照二進制與十六進制數的對應表,將四位二進制按權相加,得到的數就是一位十六進制數,然后按順序排列,小數點的位置不變。?? ??? ?
結果為:B9B.9?? ??? ?
需要注意的是,在向左(或向右)取四位時,取到最高位(最低位)如果無法湊足四位,就可以在小數點的最左邊(或最右邊)補0,進行換算。?? ?
十六進制數字轉換二進制數字:
對照二進制與十六進制數的對應表,將十六進制數分為二進制數字,用四位二進制數字按權相加,最后得到二進制數字,小數點依舊。
?
2、
1 #include <iostream>2 using namespace std;3 4 typedef struct A5 {6 char aChar;7 int aInt_2;8 short aInt;9 }TypeA; 10 11 typedef struct B 12 { 13 char bChar[3]; 14 TypeA bA; 15 double bDouble; 16 }TypeB; 17 18 int main() 19 { 20 TypeA a; 21 TypeB b; 22 cout << sizeof(a) << endl << sizeof(b) << endl; 23 return 0; 24 }輸出為 12 24
解析:
由上述對字節對齊問題的討論很容易便可以得出此題的答案。
sizeof(TypeA) = 1 + 3 + 4 + 2 = 10。 10 / 4 = 2 …… 2,故需要再補上 2 個字節,即 sizeof(TypeA) = 12;
sizeof(TypeB) = 3 + 1 + 12 + 8 = 24。之所以補上 1 個字節是因為 TypeA 類型在 struct TypeB 中的默認對齊方式
是 4 個字節(即 int 的字節大小,也即 struct TypeA 中最長的字節)。
總結
以上是生活随笔為你收集整理的仔细讨论 C/C++ 字节对齐问题⭐⭐的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 幻想迷宫
- 下一篇: oracle rac理论知识