2013-04-08 40 views
5

Theo this answer, trong đó nêu:Tại sao các hàm C++ có thể tạo mảng có độ dài thay đổi?

Trình biên dịch biết kích thước của kiểu int và do đó có thể tạo ra hướng dẫn lắp ráp ngay mà sẽ dự trữ đủ không gian trên ngăn xếp để cho foo sống ở đó.

trình biên dịch cần biết kích thước của hàm sẽ chiếm trên ngăn xếp để triển khai.

Sau đó, tại sao mã này biên dịch?

int f(int n) 
{ 
    int x[n]; 
} 

int main() 
{ 
    f(3); 
    f(5); 
    //etc 
} 

x là một mảng số nguyên, nhưng kích thước của nó không đổi, nó có thể thay đổi bất cứ lúc nào hàm được gọi.

Tôi thiếu gì ở đây?

+5

Biên dịch lại bằng '-pedantic'. – chris

+1

"erw.cpp: Trong hàm 'int f (int)': erw.cpp: 3: 12: cảnh báo: ISO C++ cấm mảng biến dài 'x' [-Wvla]" - @chris: cảm ơn, điều này có ý nghĩa hiện nay. – corazza

+0

có thể trùng lặp của [Trong sách C++, mảng bị ràng buộc phải là biểu thức liên tục, nhưng tại sao mã sau hoạt động?] (Http://stackoverflow.com/questions/5947661/in-c-books-array-bound-must-be -constant-expression-but-why-the-following-cod) –

Trả lời

8

Đây không phải là mã hợp pháp trong tiêu chuẩn C++. Nó biên dịch nhờ một phần mở rộng cụ thể cho trình biên dịch của bạn hỗ trợ variable-length arrays, là một tính năng của C99.

Nhưng một lần nữa, đây là không phải di động C++. Nếu bạn cần kích thước động, bạn có thể viết lại chức năng của bạn theo cách này:

#include <vector> 

int f(int n) 
{ 
    std::vector<int> v(n); 
} 

Nếu không, làm cho nó một khuôn mẫu và viết nó theo cách này: công việc

#include <array> 

template<std::size_t N> 
int f() 
{ 
    std::array<int, N> a; 
} 
4

Nó biên dịch vì bạn đang sử dụng tiện ích mở rộng không chuẩn. Theo nghĩa hẹp, nó không hợp lệ C++, nhưng một số trình biên dịch hỗ trợ điều này.

Trong trường hợp của bạn (3 và 5 được biết), bạn có thể sử dụng mẫu thay thế, mẫu sẽ hợp lệ hoặc trực tiếp std::vector.

template<int n> 
int f() 
{ 
    int x[n]; 
} 

//... 
f<3>(); 
0

của trình biên dịch thực sự khó khăn hơn trong trường hợp này là. Nó bây giờ cần phải phát ra mã mà sẽ - lúc chạy - tìm ra bao nhiêu bộ nhớ là cần thiết (n*sizeof(int)), và nơi để có được bộ nhớ đó từ. Bộ nhớ đó vẫn được phát hành tại cùng một vị trí như nơi mà int y[5]; sẽ được phát hành, do đó, trong khía cạnh đó không có gì thay đổi.

Một giải pháp dễ dàng cho trình biên dịch là thay đổi mã đằng sau hậu trường thành int * __x = malloc(n*sizeof(int) ... free(__x). Nó cũng có thể cần phải viết lại một số mã cho sizeof(x), nhưng có quá trình biên dịch có thể viết lại mã VLA thành mã "bình thường". Không có phép thuật cần thiết; VLA có thể được thực hiện dưới dạng đường cú pháp.

Các vấn đề liên quan