2010-07-06 40 views
7

Được rồi, ít kỳ quặc mà tôi đã khám phá với trình biên dịch C++ của tôi.C++ có thực thi các câu lệnh trả về không?

Tôi có một đoạn mã không quá phức tạp để cấu trúc lại và tôi vô tình xoay sở để thoát khỏi đường dẫn không có câu lệnh trả về. Lỗi của tôi. Mặt khác, điều này được biên soạn, và bị phân đoạn khi tôi chạy nó và con đường đó đã bị tấn công, rõ ràng.

Đây là câu hỏi của tôi: Đây có phải là lỗi trình biên dịch hay không đảm bảo rằng trình biên dịch C++ sẽ thực thi sự cần thiết cho câu lệnh trả về trong hàm trả về không có khoảng trống?

Ồ, và rõ ràng, trong trường hợp này, đó là câu lệnh if không cần thiết nếu không có người khác đi kèm. Không có gotos, không có lối thoát, không hủy bỏ.

+0

Trình biên dịch nào bạn đang sử dụng? – Dennis

+3

Nếu sử dụng gcc ['-Wreturn-type'] (http://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html), có thể với' -Werror = '. –

+0

điều tương tự cũng xảy ra với tôi với gcc 4.4 –

Trả lời

11

Cá nhân tôi nghĩ rằng đây sẽ là một lỗi:

int f() { 
} 

int main() { 
    int n = f(); 
    return 0; 
} 

nhưng hầu hết các trình biên dịch xử lý nó như một lời cảnh báo, và bạn thậm chí có thể phải sử dụng công tắc biên dịch để có được cảnh báo đó.Ví dụ: trên g ++ bạn cần -Wall để nhận:

[[email protected] NeilB]$ g++ -Wall nr.cpp 
nr.cpp: In function 'int f()': 
nr.cpp:2: warning: no return statement in function returning non-void 

Tất nhiên, với g ++ bạn phải luôn biên dịch ít nhất -Wall.

13

Không có gì đảm bảo rằng trình biên dịch C++ sẽ thực thi điều đó. Một hàm C++ có thể nhảy ra khỏi luồng điều khiển của nó bằng các cơ chế chưa biết đến trình biên dịch. Bối cảnh chuyển mạch khi C++ được sử dụng để viết một hạt nhân hệ điều hành là một ví dụ về điều đó. Một ngoại lệ không bị bắt bởi một hàm được gọi (có mã không nhất thiết phải có sẵn cho người gọi) là một ngoại lệ khác.

Một số ngôn ngữ khác, như Java, thực thi rõ ràng rằng với kiến ​​thức có sẵn tại thời gian biên dịch, tất cả các đường dẫn sẽ trả về một giá trị. Trong C++, điều này không đúng, như với nhiều dịp khác trong ngôn ngữ, như việc truy cập một mảng ngoài giới hạn của nó cũng không được kiểm tra.

+0

"Chức năng A ++ có thể nhảy ra khỏi luồng điều khiển của nó bằng các cơ chế chưa biết tới trình biên dịch." - vâng, nhưng dòng chảy sẽ được nhảy trở lại. Một chuyển đổi ngữ cảnh chuyển đổi trở lại, sau khi tất cả. Tôi thực sự không thấy điều này liên quan đến các giá trị trả về. Trường hợp duy nhất chức năng sẽ không được hoàn nguyên là nếu một ngoại lệ được ném ra. –

+0

@Không cần thiết. Ví dụ: cuộc gọi đến 'thoát' sẽ không bao giờ nhảy trở lại. –

+1

@Johannes OK, và hủy bỏ() và chấm dứt(). Nhưng trình biên dịch không thể thấy rằng những điều này phủ nhận sự cần thiết phải trả lại, trừ khi nó xử lý chúng như là "đặc biệt" theo một cách nào đó. –

4

Trình biên dịch không thực thi điều này vì bạn có kiến ​​thức về những đường dẫn nào có thể thực tế mà trình biên dịch không thực hiện được. Trình biên dịch thường chỉ biết về tệp cụ thể đó, không phải tệp khác có thể ảnh hưởng đến luồng bên trong bất kỳ hàm đã cho nào. Vì vậy, nó không phải là một lỗi.

Trong Visual Studio, mặc dù, đó là cảnh báo. Và chúng ta nên chú ý đến tất cả các cảnh báo .... đúng không? :)

Chỉnh sửa: Dường như có một số cuộc thảo luận về thời điểm điều này có thể xảy ra. Đây là một ví dụ được sửa đổi nhưng thực tế từ thư viện mã cá nhân của tôi;

enum TriBool { Yes, No, Maybe }; 

TriBool GetResult(int input) { 
    if (TestOne(input)) { 
     return Yes; 
    } else if (TestTwo(input)) { 
     return No; 
    } 
} 

Hãy theo tôi vì đây là mã cũ. Ban đầu có một "khác trở lại có thể" trong đó. :) Nếu TestOne và TestTwo nằm trong một đơn vị biên dịch khác thì khi trình biên dịch truy cập mã này, nó không thể biết TestOne và TestTwo có thể trả về false cho một đầu vào đã cho hay không. Bạn, là lập trình viên đã viết TestOne và TestTwo, biết rằng nếu TestOne không thành công thì TestTwo sẽ thành công. Có thể có những phản ứng phụ của những xét nghiệm đó nên chúng phải được thực hiện. Nó sẽ là tốt hơn để viết nó mà không có "khác nếu"? Có lẽ. Có lẽ. Nhưng vấn đề là đây là hợp pháp C++ và trình biên dịch không thể biết nếu nó có thể thoát ra mà không có một câu lệnh trả về. Đó là, tôi đồng ý, xấu xí và không tốt mã hóa nhưng nó là hợp pháp và Visual Studio sẽ cung cấp cho bạn một cảnh báo nhưng nó sẽ biên dịch.

Hãy nhớ rằng C++ không phải là về việc bảo vệ bạn khỏi chính bạn. Đó là về việc cho phép bạn làm những gì trái tim của bạn mong muốn trong những hạn chế của ngôn ngữ ngay cả khi điều đó bao gồm việc tự bắn mình vào chân.

+0

Điều này không có ý nghĩa. Trình biên dịch phải có kiến ​​thức về những đường dẫn nào có thể để biên dịch mã. –

+1

@Neil tôi nghĩ anh ấy có một điểm. Trình biên dịch không phải lúc nào cũng biết tại * thời gian biên dịch *. Giống như bạn không có đầu mối khi bạn đăng bình luận của bạn rằng tôi sẽ đăng một câu trả lời cho nó. Nhưng bây giờ bạn biết, và có thể có biện pháp phòng ngừa để trả lời lần lượt, hoặc không. Hoặc bạn hoàn toàn ngạc nhiên, giống như C++ sẽ, và làm những điều không xác định :) –

+1

Đó là IMHO vô nghĩa. Biểu đồ dòng điều khiển của bất kỳ hàm đã cho nào được trình biên dịch biết đến một cách hoàn hảo sau khi phân tích mã của nó. Nó có thể là trường hợp mà một số cạnh không bao giờ đi qua trong khi thực hiện mã (suy nghĩ về xác nhận), nhưng trình biên dịch xử lý nó như vậy và tất cả nó gây ra chỉ là một (quá) bảo thủ đoán. – jpalecek

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