2014-03-13 62 views
3

的靜態運行時已知長度我寫以下代碼:如何GCC分配陣列

int tester(int n) 
{ 
    int arr[n]; 
    // ... 
} 

此代碼編譯,沒有警告,使用克++。

我的問題是 - 如何?參數n僅在運行時就已知,數組是靜態分配的。 gcc如何編譯這個?

+0

你問這是如何實現,或者爲什麼它編譯,因爲它不是合法的C++? – juanchopanza

+0

@juanchopanza這是如何實現的? – elyashiv

回答

7

這是GCC爲C++提供的擴展,儘管C99自C99以來已適當支持可變長度數組(「VLA」)。

實現不是非常困難;在一個典型的調用堆棧實現中,該函數只需要保存堆棧幀的基礎,然後按照動態指定的量推進堆棧指針。 VLA總是會提出這樣的警告:如果數字太大,你會得到未定義的行爲(在堆棧溢出中表現出來),這使得它們比使用更合適,比如std::vector

曾經有人試圖給C++增加一個類似的特性,但是這在類型系統方面出人意料地困難(例如arr的類型是什麼?它在函數模板中是如何得到的? )。這個問題在C語言中不太明顯,它有一個簡單得多的類型系統和對象模型(但是可以說,你仍然可以爭辯說因爲有了VLA,C會更糟糕,相當一部分標準花在了它們上面,而語言會沒有他們就更簡單了,而且不一定窮)。

+0

它確實被添加到C++中,並且問題得到了解決(請參閱[N3639](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3639.html)),但是拉出並轉移到TS覆蓋陣列擴展 –

+0

@JonathanWakely據我瞭解,該提案被拆分成一個單獨的TS,因爲它被批准後,足夠的更新不斷更新,以表明它沒有真正完成或足夠穩定確信一切都已經真正解決了正確的方法。 – bames53

+0

如果數組首先表現得理智(例如,沒有指針衰減),那麼C++中的動態數組可能會容易得多,因爲類型系統實際上會幫助,而不是主動阻塞。 – bames53

3

GNU C庫提供了一個函數來分配堆棧上的內存 - alloca(3)。它只是遞減堆棧指針,從而在其上創建一些臨時空間。 GCC使用alloca(3)來實現C99可變長度數組 - 它首先遞減函數序言中的堆棧指針,以便爲編譯時已知大小的所有自動變量創建空間,然後使用alloca(3)進一步減小它併爲arr騰出空間大小在運行時確定。優化器可能實際上融合了這兩個遞減。

int tester(int n) 
{ 
    int arr[n]; 
    return 0; 
} 

編譯成

;; Function tester (tester) 

tester (int n) 
{ 
    int arr[0:D.1602D.1602] [value-expr: *arr.1]; 
    int[0:D.1602D.1602] * arr.1; 
    long unsigned int D.1610D.1610; 
    int n.0; 
    ... 

<bb 2>: 
    n.0 = n; 
    ... 
    D.1609D.1609 = (long unsigned int) n.0; 
    D.1610D.1610 = D.1609D.1609 * 4; 
    D.1612D.1612 = __builtin_alloca (D.1610D.1610); <----- arr is allocated here 
    arr.1 = (int[0:D.1602D.1602] *) D.1612D.1612; 
    ... 

這相當於下面的C代碼:

int tester(int n) 
{ 
    int *arr = __builtin_alloca(n * sizeof(int)); 
    return 0; 
} 

__builtin_alloca()是GCC的內部實現alloca(3)

+0

'alloca'不是C標準庫的一部分。 –

+0

@KerrekSB,true - 已修復。 –