本文屬於「C 編譯器剖析」系列,聚焦中間代碼生成階段如何將高層陣列/結構體訪問轉換為基於基址加偏移的低層操作。
原始碼:
int a[10][20];
struct { int x; float y; } s;
a[i][j] = 5;
s.y = 3.14;
編譯器必須在中間代碼階段計算出相對基址的位元組偏移量,生成類似:
t1 = i * 20 + j // 陣列元素索引計算 t2 = t1 * 4 // 元素大小 4 bytes t3 = &a + t2 // 實際位址 *t3 = 5 // 存儲 t4 = offsetof(s, y) // 結構體成員偏移(編譯期常數) t5 = &s + t4 *t5 = 3.14
a[i][j] 偏移 = (i * COL + j) * sizeof(element)offsetof 巨集)。p += stride)。for (i=0; i<N; i++) {
a[i][k] = b[i] * c; // k, c 為循環不變量
}
優化後中間代碼:
base_a_k = &a + k * sizeof(row) // 循環外計算
base_b = &b
for (i=0; i<N; i++) {
*(base_a_k + i * row_stride) = *base_b++ * c;
}
「偏移量訪問」是連接高層抽象與硬體記憶體模型的橋樑。編譯器前端將語法樹降維為帶偏移的指標運算,中端對偏移計算進行常數折疊、強度削減、循環不變量外提等優化,後端再映射到目標指令集的寻址模式(如 x86 的 [base + index*scale + disp])。