一、什麼是字節對齊

編譯器為了讓 CPU 訪問更快,會把變量放在“合適的地址”上,而不是緊挨着放。

為什麼要對齊?

  • CPU 訪問 4 字節對齊的 int 比非對齊快
  • 某些平台(如 ARM)不對齊直接崩
  • 所以編譯器會自動插空字節(padding)


二、對齊的核心規則

規則 1:成員對齊規則

每個成員的起始地址,必須是它“對齊值”的整數倍

規則 2:結構體整體對齊

結構體總大小,必須是“最大成員對齊值”的整數倍

規則 3:不夠就補 padding

內存佈局只和“類型 + 順序 + 對齊規則”有關,和變量裏存的“具體值”無關

鐵律

結構體大小 ≠ 成員大小簡單相加

1️⃣ 每個成員的起始地址必須是它“對齊值”的整數倍
2️⃣ 整個結構體的大小必須是“最大對齊值”的整數倍


三、計算結構體大小

示例1:

#include <stdio.h>
#include <string.h>
#include <cstdlib>

// 計算結構體大小,內存對齊,按照最大成員對齊
struct Worker { // 定義一個結構體,相當於java的class
	char name[10]; // 10
	int age; // 4
	double salary; // 8
};

int main() {
	
	int size = sizeof(struct Worker);
	printf("Size of Worker struct: %d bytes\n", size); // Size of Worker struct: 24 bytes
	return 0;
}

排內存:

name : 10字節

age : 按上面説的 規則1(每個成員的起始地址,必須是它“對齊值”的整數倍),10 不是 age 4字節的整數倍,所以要 + 2,此時到 age 時字節總數為 :10 + 2 + 4 = 16 字節

double: 前面 16 字節滿足 double 8 字節整數倍,所以此時字節數為:16 + 8 = 24 字節

所以結構體 Worker 所佔用的內存就是 24 字節


示例2:

#include <stdio.h>
#include <string.h>
#include <cstdlib>

struct date {
	int year;
	int month;
	int day;
};

struct Worker { // 定義一個結構體,相當於java的class
	int number; // 4 字節
	char name[10]; // 10
	int age; // 4
	char sex; // 1 字節
	struct date hireDate; // 12 字節
};

int main() {
	
	int size = sizeof(struct Worker);
	
	printf("Size of Worker struct: %d bytes\n", size); // Size of Worker struct: 36 bytes
	return 0;
}

排內存:

4 + 10 + 2(padding) + 4 + 1 + 3(padding) + 12 = 36 字節


number: 4 name[10] : 4 + 10 = 14 age: 14 不滿足 age 四字節倍數要求,需要補齊後繼續排,14 + 2 + 4 = 20 sex: 20 + 1 = 21 , char最小,其實放哪都可以,一般最小對齊的要放後面,節省內存 date: struct date 的對齊值是 4 , 21 + 3 + 12 = 36 36 滿足最大對齊 4 字節倍數要求,所以 Worker 所佔內存就是 36


調整屬性順序

對齊要求大的放前面,小的放後面

struct Worker {
    int number;        // 4 對齊
    int age;           // 4 對齊
    struct date hireDate; // 4 對齊
    char name[10];     // 1 對齊
    char sex;          // 1 對齊
};

number : 4

age : 4 + 4 = 8

hireDate: 4 + 4 + 12 = 20

name: 4 + 4 + 12 + 10 = 30

sex : 4 + 4 + 12 + 10 + 1 = 31

最後:因為整個結構體的大小必須是“最大對齊值”的整數倍

所以 31 不是 最大對齊值 4 字節的整數倍,對齊 1 個字節 變成 32

此時結構體 Worker 的大小就是 32 字節!

同樣的屬性,比上面那個排列方式 節省 4 字節內存!


四、最後

對齊要求大的放前面

先把“大型傢俱(高對齊)”擺好

對齊要求小的放後面

最後用“小雜物(char)”填縫