2012-03-30 50 views
10

Nếu hàm có kiểu trả về khác với void và hàm không trả về bất kỳ thứ gì, thì tôi đoán trình biên dịch trả về giá trị rác (có thể được xem là giá trị chưa được khởi tạo). Nó xảy ra vào thời gian biên dịch, vậy tại sao nó không nên ném một lỗi?Nếu một hàm trả về không có giá trị, với kiểu trả về hợp lệ, thì trình biên dịch có thể vứt rác không?

Ví dụ,

int func1() { 
    return; // error 
} 

int func2() { 
    // does not return anything 
} 

Thứ hai func2 nên ném ra một lỗi, nhưng nó không. Có lý do gì không? Suy nghĩ của tôi là như vậy mà, nó có thể được xem như là một giá trị chưa được khởi tạo, vì vậy nếu chúng ta cần phải ném ra một lỗi trong trường hợp thứ hai, sau đó chúng ta cần phải ném lỗi, nếu một giá trị chưa được định hình, nói

int i; // error 
    int i = 6; // okay 

Bất kỳ suy nghĩ, hay đây là một câu hỏi trùng lặp? Tôi đánh giá cao sự giúp đỡ của bạn.

+2

Có phải C hoặc C++ không? Bạn có nhận được lỗi biên dịch hoặc cảnh báo không? Bạn đang sử dụng trình biên dịch nào? – littleadv

+1

Bật cảnh báo của bạn. –

+0

có thể trùng lặp của [tùy chọn gcc: cảnh báo về các chức năng không có hiệu lực mà không có câu lệnh trả lại] (http://stackoverflow.com/questions/9924570/gcc-options-warning-on-non-void-functions-without-a- return-statement) –

Trả lời

15

Trong C++, mã này đã không xác định:

[stmt.return]/2 ... chảy ra khỏi cuối của một hàm tương đương với một sự trở lại không có giá trị; điều này dẫn đến hành vi không xác định trong hàm trả về giá trị. ...

Hầu hết các trình biên dịch sẽ tạo cảnh báo cho mã tương tự như trong câu hỏi. Tiêu chuẩn C++ không yêu cầu đây là lỗi thời gian biên dịch vì trong trường hợp chung, rất khó để xác định chính xác liệu mã có thực sự chạy hết chức năng hay không, hoặc nếu hàm thoát ra thông qua một ngoại lệ (hoặc một longjmp hoặc cơ chế tương tự).

Cân nhắc

int func3() { 
    func4(); 
} 

Nếu func4() ném, sau đó mã này là hoàn toàn tốt. Trình biên dịch có thể không nhìn thấy định nghĩa của func4() (do biên dịch riêng), và vì vậy không thể biết liệu nó có ném hay không.

Hơn nữa, ngay cả khi trình biên dịch có thể chứng minh rằng func4() không ném, nó vẫn phải chứng minh rằng func3() thực sự được gọi trước khi nó có thể từ chối hợp pháp chương trình. Phân tích như vậy yêu cầu kiểm tra toàn bộ chương trình, không tương thích với việc biên dịch riêng biệt và thậm chí không thể có được trong trường hợp chung.

+2

Nhiều ngôn ngữ bao gồm C# và Java sẽ yêu cầu câu lệnh 'return someValue;' trong ví dụ trên, mặc dù nó không bao giờ có thể được thực hiện. Thiết kế ngôn ngữ là về sự cân bằng và giá trị tương đối của các chẩn đoán hữu ích so với nhu cầu thường xuyên đối với mã ngớ ngẩn để xoa dịu trình biên dịch. Tôi không đồng ý với nhiều quyết định Java/C#, nhưng điều này đặc biệt mà tôi không hề có. – supercat

+1

@supercat: Câu trả lời của tôi được hiểu là: "C++ làm cho hành vi không xác định này, nhưng không may là không đủ để các trình biên dịch thực sự từ chối mã này, bởi vì nó là không thể (tại thời gian biên dịch) hoặc không phải là hành vi không xác định thực tế xảy ra. " Điều đó không có nghĩa là không thể thiết kế một ngôn ngữ khác mà từ chối các chương trình * có thể hợp lệ nhưng không phù hợp với mô hình an toàn của hệ thống kiểu ngôn ngữ đó (mà C++ đã làm, cho những thứ khác) . – Mankarse

4

Trong C, thực sự là hợp pháp đối với hàm không có giá trị để hoàn thành mà không trả lại giá trị, miễn là mã gọi không cố gắng sử dụng giá trị trả lại.

Mặt khác, câu lệnh return không có biểu thức không được phép xuất hiện trong chức năng không trống.

Các bộ phận có liên quan của các tiêu chuẩn C99 được §6.9.1 đối với trường hợp thứ nhất:

Nếu } rằng chấm dứt một chức năng được đạt tới, và giá trị của cuộc gọi chức năng được sử dụng bởi người gọi , hành vi không xác định.

và §6.8.6.4 đối với trường hợp thứ hai:

Một tuyên bố return mà không có một biểu hiện sẽ chỉ xuất hiện trong một hàm có kiểu trả về là void.

+0

Đoạn đầu tiên là chính xác cho C, nhưng không phải cho C++. –

+1

@KeithThompson: Đó là lý do tại sao tôi bắt đầu với "In C ..." – caf

+0

Không chắc tôi đã bỏ lỡ điều đó như thế nào. (Nhưng câu hỏi đã được gắn thẻ cả C và C++.) –

2

Cả hai chức năng của bạn đều bị ảnh hưởng. Sự khác biệt giữa chúng là func1 của bạn vi phạm các quy tắc về cách tuyên bố return có thể được sử dụng trong khi func2 của bạn là hành vi không xác định. Tuyên bố return trong số func1 của bạn là bất hợp pháp và việc triển khai phải chẩn đoán điều này. Việc thiếu báo cáo trả về trong số func2 của bạn là hành vi không xác định. Hầu hết các trình biên dịch sẽ chẩn đoán điều này, nhưng không phải. hành vi

+0

Trong C, hàm đầu tiên không bị hỏng. Hành vi này chỉ không xác định nếu người gọi thực sự cố gắng sử dụng giá trị trả về. – caf

+0

Vâng, tôi đồng ý, đây là một thử nghiệm và cố gắng tìm hiểu lý do tại sao C commite có cách này ... – howtechstuffworks

9

Trong C, trích dẫn N1256 6.9.1p12:

Nếu } rằng chấm dứt một chức năng được đạt tới, và giá trị của cuộc gọi chức năng được sử dụng bởi người gọi, hành vi này là không xác định.

Vì vậy, nó là hợp pháp (mà là một ý tưởng tồi) cho một hàm phi khoảng trống để không trả về một giá trị, nhưng nếu nó làm như vậy người gọi cố gắng sử dụng kết quả, hành vi này là không xác định. Lưu ý rằng nó không nhất thiết chỉ trả lại một số giá trị tùy ý; theo như tiêu chuẩn là có liên quan, bất cứ điều gì là có thể.

Pre-ANSI C không có từ khóa void, do đó cách viết hàm không trả lại giá trị là loại bỏ kiểu trả về, làm cho nó trở về hoàn toàn int. Yêu cầu câu lệnh return trong hàm trả về giá trị sẽ có mã cũ bị hỏng. Nó cũng sẽ yêu cầu phân tích thêm bởi trình biên dịch để xác định rằng tất cả các đường dẫn mã nhấn một tuyên bố return; phân tích như vậy là hợp lý cho các trình biên dịch hiện đại, nhưng có thể là một gánh nặng quá mức khi C được chuẩn hóa lần đầu tiên.

C++ hơi nghiêm ngặt hơn. Trong C++:

chảy ra khỏi cuối của một hàm tương đương với một trở với không có giá trị; điều này dẫn đến hành vi không xác định trong hàm trả về giá trị.

vì vậy hành vi không xác định liệu người gọi có cố gắng sử dụng kết quả (không tồn tại) hay không.

C và C++ biên dịch chắc chắn thể cảnh báo về việc thiếu return báo cáo, tương đương khoảng đường dẫn điều khiển mà rơi ra khỏi cuối của một hàm mà không thực hiện một tuyên bố return, nhưng các tiêu chuẩn tương ứng không đòi hỏi họ phải làm như vậy.

+2

Phân tích như vậy chỉ hợp lý trong các trường hợp đơn giản - trong các trường hợp phức tạp, trình biên dịch có thể thậm chí không có đủ thông tin để biết rằng nó sẽ luôn đạt được một câu lệnh 'return'. – caf

+0

Có thể yêu cầu tất cả các đường dẫn điều khiển có thể thực hiện câu lệnh 'return'; Tôi nghĩ C# làm như vậy. Ví dụ, '{if (1) {return 42; } else {puts ("Không trở lại đây"); } 'sẽ vi phạm một yêu cầu như vậy, mặc dù nó không thực sự có thể để tránh' return'. C và C++ không làm vậy. –

+0

@Keith: Không thể thực hiện được. Xem câu trả lời của Mankarse. –

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