2008-11-23 55 views
17

Tôi có một hàm đơn giản trong đó một mảng được khai báo với kích thước tùy thuộc vào tham số là int.Kích thước mảng C++ phụ thuộc vào tham số hàm gây ra lỗi biên dịch

void f(int n){ 
     char a[n]; 
    }; 

    int main() { 
     return 0; 
    } 

Đoạn mã này biên dịch tốt trên GNU C++, nhưng không phải trên MSVC 2005.

tôi nhận được các lỗi biên dịch sau:

.\main.cpp(4) : error C2057: expected constant expression 
    .\main.cpp(4) : error C2466: cannot allocate an array of constant size 0 
    .\main.cpp(4) : error C2133: 'a' : unknown size 

tôi có thể làm gì để khắc phục điều này?

(Tôi quan tâm đến làm công việc này với MSVC, mà không sử dụng mới/xóa)

Trả lời

29

Những gì bạn đã tìm thấy nó là một trong những phần mở rộng của trình biên dịch Gnu với ngôn ngữ C++. Trong trường hợp này, Visual C++ là hoàn toàn chính xác. Mảng trong C++ phải được định nghĩa với kích thước là biểu thức hằng số biên dịch.

Có một tính năng được thêm vào C trong bản cập nhật năm 1999 cho ngôn ngữ đó được gọi là các mảng độ dài thay đổi, trong đó điều này là hợp pháp. Nếu bạn có thể tìm thấy trình biên dịch C hỗ trợ C99, điều này không dễ. Nhưng tính năng này không phải là một phần của tiêu chuẩn C++, không phải là nó sẽ được thêm vào trong bản cập nhật tiếp theo cho tiêu chuẩn C++.

Có hai giải pháp trong C++. Đầu tiên là sử dụng một std :: vector, thứ hai là chỉ để sử dụng toán tử new []:

char *a = new char [n]; 

Trong khi tôi đang viết câu trả lời của tôi, một số khác gửi một gợi ý để sử dụng _alloca. Tôi sẽ khuyên bạn nên chống lại điều đó. Bạn sẽ chỉ trao đổi một phương thức không chuẩn, không di động cho một phương thức khác như trình biên dịch cụ thể.

+1

Vâng, nhưng phân bổ từ heap, mà "mới" hiện, là khác nhau nhiều từ phân bổ từ ngăn xếp đó là những gì OP đang cố gắng làm. –

+0

Không quá nhiều lo lắng về hiệu suất cho thời điểm này, tôi nghĩ rằng nó là tự nhiên để làm việc ... nhưng nếu nó không phải là một phần của tiêu chuẩn C++ sau đó tôi hiểu – xxxxxxx

+0

Re: _alloca: OP chỉ hỏi về việc lấy mã tương đương làm việc trên MSVC và không sử dụng mới/xóa. –

9

phương pháp bạn phân bổ từ ngăn xếp là một phần mở rộng ++ g. Để thực hiện tương đương theo MSVC, bạn cần sử dụng _alloca:

char *a = (char *)_alloca(n); 
+0

Ồ để phân bổ trên ngăn xếp! thật tuyệt vời :) Cảm ơn! – xxxxxxx

+1

Lưu ý nhận xét này từ trang manoca alloca: LGSI Chức năng alloca phụ thuộc vào máy và trình biên dịch. Trên nhiều hệ thống, việc thực hiện nó là lỗi. Việc sử dụng nó không được khuyến khích. –

+0

Vâng, nhưng nó hoạt động chắc chắn theo MSVC, đó là những gì OP đã cố gắng để có được mã của mình làm việc theo. Tôi đã sử dụng nó trong nhiều năm. –

2

Bạn có thể sử dụng mới/xóa để cấp phát/bộ nhớ trống trên heap. Điều này là chậm hơn và có thể dễ bị lỗi hơn khi sử dụng char [n], nhưng nó không phải là một phần của tiêu chuẩn C++, thật đáng buồn.

Bạn có thể sử dụng lớp mảng có phạm vi tăng cường cho phương pháp ngoại lệ an toàn để sử dụng [] mới. xóa [] được tự động gọi trên a khi nó nằm ngoài phạm vi.

void f(int n) { 
    boost::scoped_array<char> a(new char[n]); 

    /* Code here. */ 
} 

Bạn cũng có thể sử dụng std :: vector, và dự trữ() một số byte:

void f(int n) { 
    std::vector<char> a; 
    a.resize(n); 

    /* Code here. */ 
} 

Nếu bạn làm muốn sử dụng char [n], biên dịch như C99 mã thay vì C++ mã.

Nếu bạn hoàn toàn phải phân bổ dữ liệu trên ngăn xếp vì một lý do nào đó, hãy sử dụng _alloca hoặc _malloca/_freea, là các tiện ích được cung cấp bởi thư viện MSVC và như vậy.

+0

có nhưng tôi không hiểu tại sao g + + không có vấn đề với điều này trong khi MSVC thất bại – xxxxxxx

+0

Điều này là sai vì nó phân bổ từ đống. Anh ta muốn phân bổ trên stack là phiên bản g ++. Lý do mà MSVC không biên dịch phiên bản gốc là nó là một phần mở rộng g ++. –

+0

Anh ấy không thể có trên ngăn xếp với MSVC. Ông có thể có nó trên đống, hoặc có nó được kích thước không đổi, không có cách nào để phân bổ một mảng có kích thước khác nhau trên stack với MSVC. –

5

Bạn đang sử dụng thứ gì đó không phải là tiêu chuẩn. Trên thực tế nó là tiêu chuẩn C nhưng không phải C++. Đặc biệt thế nào!

Giải thích thêm một chút, các mảng ngăn xếp có kích thước thời gian chạy không phải là một phần của C++, nhưng là một phần của C99, tiêu chuẩn mới nhất cho C.Đó là lý do tại sao một số trình biên dịch sẽ nhận được nó, trong khi những người khác thì không. Tôi khuyên bạn nên hạn chế sử dụng nó, để tránh các vấn đề tương thích với trình biên dịch.

Việc triển khai thay thế chức năng sẽ sử dụng mới và xóa, như được đăng bởi strager.

+1

Nó không phải là "đặc biệt" ở tất cả ..! –

1

Thông thường trong C (ngoại trừ C99 trình biên dịch như những người khác đã chỉ ra) và C++, nếu bạn muốn cấp phát bộ nhớ trên ngăn xếp, kích thước của những gì bạn muốn phân bổ phải được biết tại thời gian biên dịch. Các biến cục bộ được cấp phát trên ngăn xếp, do đó một mảng có độ dài phụ thuộc vào tham số hàm tại thời gian chạy vi phạm quy tắc này. Klein là đúng để chỉ ra rằng việc sử dụng các nhà điều hành 'mới' là một cách để giải quyết vấn đề này:

 

char *a = new char [n]; 

'a' vẫn là một biến địa phương cấp phát trên stack, nhưng thay vì toàn bộ mảng (có độ dài biến đổi), nó chỉ là một con trỏ tới một mảng (luôn luôn có cùng kích thước, và do đó được biết đến tại thời gian biên dịch). Mảng được cấp phát trên heap, thường đóng vai trò đối tác của chồng - ngăn xếp dành cho những thứ có kích thước được biết đến tại thời gian biên dịch và heap dành cho những thứ có kích thước không được biết tại thời gian biên dịch.

1

Có hợp lý để sử dụng vector<> thay vì một mảng không? Hoặc, vì bạn đang thay thế một số char *, một số std::string? Những người làm việc tốt với kích thước thời gian chạy, mặc dù có thể có các lý do khác không sử dụng chúng.

2

mảng độ dài biến được giới thiệu trong C99. Nó được hỗ trợ trong gcc nhưng không phải là msvc. Theo một người trong nhóm MSVC, Microsoft không có kế hoạch hỗ trợ tính năng này trong trình biên dịch c/C++ của họ. Ông đề nghị sử dụng std :: vector trong những trường hợp đó.

Lưu ý rằng C99 không yêu cầu mảng được cấp phát trên ngăn xếp. Trình biên dịch có thể phân bổ nó trên heap. Tuy nhiên, gcc không phân bổ mảng trên ngăn xếp.

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