DEV Community

Cover image for 這兩個 C++ 結構為什麼大小不一樣?
codemee
codemee

Posted on

這兩個 C++ 結構為什麼大小不一樣?

C++ 有些細節雖然不知道可能不會影響你的程式碼正確執行, 不過卻可能影響你的程式耗用的記憶體。舉例來說, 底下這個程式定義了兩個幾乎相同的結構, 只是成員的順序不一樣, 不過如果顯示這兩個結構的大小, 就會發現 data2 要比 data1 多耗費了 4 個位元組:

#include <iostream>
using namespace std;

struct data1 {
    char c1;
    char c2;
    int i1;
    int i2; 
};

struct data2 {
    char c1;
    int i1;
    char c2;
    int i2; 
};

int main() {
    cout << "sizeof(data1) = " << sizeof(data1) << "\n";
    cout << "sizeof(data2) = " << sizeof(data2) << "\n";
    return 0;
}
Enter fullscreen mode Exit fullscreen mode

實際執行結果如下:

sizeof(data1) = 12
sizeof(data2) = 16
Enter fullscreen mode Exit fullscreen mode

要理解為什麼, 就必須理解 C++ 中個別型態的位址對齊 (alignment)

位址對齊 (alignment)

在 C++ 中, 為了存取記憶體效率的關係, 不同型態的物件必須放在特定數值倍數的位址上, 這就稱為位址對齊。你可以透過 alignof 運算子得知指定型態物件的位置對齊數值:

#include <iostream>
using namespace std;

int main()
{
    cout << "alignof(int): " << alignof(int) << endl; // 4
    cout << "alignof(double): " << alignof(double) << endl; // 8
    cout << "alignof(char): " << alignof(char) << endl; // 1
    cout << "alignof(float): " << alignof(float) << endl; // 4
    return 0;
}
Enter fullscreen mode Exit fullscreen mode

輸出結果如下:

alignof(int): 4
alignof(double): 8
alignof(char): 1
alignof(float): 4
Enter fullscreen mode Exit fullscreen mode

int 為例, 如果現在可用的記憶體位址從 1017 開始, 若要配置一個 int 變數, 因為它的位址對齊數值是 4, 就必須往後到 4 的倍數, 也就是位址 1020 開始才能配置。反觀 char, 它的位址對齊數值是 1, 所以如果是要配置 char 變數, 就可以直接從 1017 配置, 不需要移動。

位址對齊照成的補空 (padding)

剛剛看到的 int 變數例子, 就會浪費 1017 到 1019 之間的 3 個位元組, 這稱為補空 (padding), 也就是照成文章一開始兩個成員相同但順序不同的結構大小不同的原因。

data1 為例:

struct data1 {
    char c1;
    char c2; // 這裡需要補空 2 個位元組
    int i1;
    int i2; 
};
Enter fullscreen mode Exit fullscreen mode

因為 char 的位址對齊數值為 1, 所以前兩個 char 成員可以相鄰配置, 但是 int 的位址對齊數值為 1, 所以在這兩個 char 成員之後要補空 2 個位元組, 變成佔用 4 個位元組, 加上後面兩個 int 個別佔 4 個位元組, 所以共佔用 12 個位元組。

以下則是 data2

struct data2 {
    char c1; // 這裡需要補空 3 個位元組
    int i1;
    char c2; // 這裡需要補空 3 個位元組
    int i2; 
};
Enter fullscreen mode Exit fullscreen mode

因為 charint 成員交錯, 所以每個 char 成員之後需要補空 3 個位元組, 才能讓 int 成員位址對齊 4 的倍數, 導致兩個 char 成員都佔用了 4 個位元組, 加上兩個 int 成員, 所以總共佔用了 16 個位元組。

瞭解這個差異後, 你就可以在必要的時候, 調整成員的順序, 減少記憶體的用量了。

Top comments (0)