今天同學在群組裡急急忙忙 @ 我,以為發生什麼大事,結果貼了一段程式碼:
#include <stdio.h>
int main() {
int n;
scanf("%d", &n);
int data[n];
return 0;
}
第一反應是:這是哪位新手寫的爛代碼!結果對方說 GCC 編譯通過了,我親自測試,Visual Studio 直接報錯紅線,但 Dev-C++ 使用 GCC 確實能編譯通過。這讓我陷入沉思:難道 GCC 有 bug?大學 C 語言課老師反覆強調 C/C++ 沒有變長數組(除非用 new 動態分配),但 GCC 是全球廣泛使用、經過無數人測試的編譯器,這該如何解釋?
GCC 理解了程式設計師的意圖,不再死板遵守舊標準。為什麼它能這樣做?這違反 C 標準嗎?從 C 標準角度分析:C89/C90 確實規定陣列大小必須為常數表達式,但 C99 標準正式引入了變長數組(VLA)。GCC 作為 C99 的早期實作者,支援此特性。即使在 C11 中 VLA 變為可選特性,GCC 仍保留支援。
每個進程啟動時,作業系統會分配一塊堆疊空間。編譯器利用這塊堆疊實現「變長數組」:在執行期根據變數 n 的值,將堆疊指針向下移動相應位元組,把這段空間當作陣列使用。函數返回時,堆疊指針自動恢復,無需手動釋放。這就是為什麼 VLA 不能用於靜態或全域變數,也不能在結構體中使用的原因。
幾乎每個編譯器對 C 標準中模糊地帶都有自己的解讀。MSVC 長期不支援 VLA,堅持 C89 風格;Clang 跟隨 GCC 支援;Intel ICC 也支援。作為開發者,應了解目標編譯器的支援程度,必要時使用 malloc/free 或 C++ 的 std::vector 以確保可移植性。
理解編譯器如何利用堆疊實現 VLA,有助於我們寫出更高效、更安全的程式碼,也能在面試中自信解釋這類「違反直覺」的現象。