2010-08-04 35 views
19

Tôi vừa có một số hành vi kỳ lạ từ phiên bản g ++ cho Windows mà tôi có với Strawberry Perl. Nó cho phép tôi bỏ qua một tuyên bố trở lại.Bỏ qua tuyên bố trả về trong C++

Tôi có một chức năng thành viên đó trả về một cấu trúc gồm hai con trỏ, gọi là boundTag:

struct boundTag Box::getBound(int side) { 
    struct boundTag retBoundTag; 
    retBoundTag.box = this; 
    switch (side) 
    { 
     // set retBoundTag.bound based on value of "side" 
    } 
} 

Chức năng này đã cho tôi một số lượng xấu, và tôi phát hiện ra rằng nó không có câu lệnh return. Tôi đã có nghĩa là để trở về retBoundTag nhưng quên thực sự viết báo cáo trở lại. Khi tôi đã thêm return retBoundTag; mọi thứ đều ổn.

Nhưng tôi đã thử nghiệm chức năng này và nhận được kết quả chính xác boundTag từ nó. Ngay cả bây giờ, khi tôi loại bỏ câu lệnh return, g ++ biên dịch nó mà không cần cảnh báo. WTF? Liệu nó có trả về retBoundTag không?

+5

Bạn nên biên dịch bằng '-Wall'. Thiếu các câu lệnh trả về bị bắt bởi '-Wreturn-type'. – jweyrich

+0

Tôi có xu hướng biến cảnh báo về một sự trở lại bị thiếu thành một lỗi với: '-Werror = return-type'. Đã cứu tôi rất nhiều thời gian. –

Trả lời

16

Bỏ qua câu lệnh return trong hàm non-void [Ngoại trừ main()] và sử dụng giá trị trả về trong mã của bạn gọi Undefined Behaviour.

ISO C++ - 98 [Mục 6.6.3/2]

Một tuyên bố trở lại với một biểu thức có thể được sử dụng chỉ trong chức năng trả về giá trị; giá trị của biểu thức là được trả lại cho người gọi hàm. Nếu được yêu cầu, biểu thức sẽ được chuyển đổi hoàn toàn thành kiểu trả về của hàm mà trong đó nó xuất hiện . Tuyên bố trả về có thể liên quan đến việc xây dựng và sao chép một đối tượng tạm thời (class.temporary). Chảy ra khỏi đầu của một hàm tương đương với một trả về 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í dụ

int func() 
{ 
    int a=10; 
    //do something with 'a' 
    //oops no return statement 
} 


int main() 
{ 
    int p=func(); 
    //using p is dangerous now 
    //return statement is optional here 
} 

chung g ++ cho một warning: control reaches end of non-void function. Thử biên dịch với tùy chọn -Wall.

+7

Bỏ qua tuyên bố trả về là tốt. Việc thực thi đạt đến kết thúc của một hàm mà không gặp phải một câu lệnh trả về kết quả trong hành vi không xác định. Bạn có thể quay trở lại trước khi đến cuối hàm, hoặc bỏ qua một ngoại lệ, hoặc không bao giờ bỏ đi, và tất cả sẽ được xác định rõ. –

+0

tại sao sử dụng 'p' là nguy hiểm? – ajay

+2

@ajay: Đó là vì không chứa bất kỳ giá trị được chỉ định nào. –

12

C và C++ không yêu cầu bạn phải có tuyên bố return. Nó có thể không cần thiết để có một, bởi vì các chức năng đi vào một vòng lặp vô hạn, hoặc bởi vì nó ném một ngoại lệ.

Prasoon đã trích dẫn phần có liên quan của tiêu chuẩn:

[Mục 6.6.3/2]

Một tuyên bố trở lại với một biểu thức có thể được sử dụng chỉ trong chức năng trả về giá trị; giá trị của biểu thức được trả về cho người gọi hàm. Nếu được yêu cầu, biểu thức được chuyển đổi hoàn toàn thành kiểu trả về của hàm mà nó xuất hiện. Một câu lệnh return có thể liên quan đến việc xây dựng và sao chép một đối tượng tạm thời (class.temporary). Chảy ra khỏi đầu của một hàm tương đương với một trả về 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ị.

Điều đó có nghĩa là không có câu trả lại là ok. Nhưng đến cuối chức năng mà không quay trở lại là hành vi không xác định.

Trình biên dịch không phải lúc nào cũng phát hiện được các trường hợp này, vì vậy nó không phải là lỗi biên dịch (nó phải giải quyết vấn đề dừng để xác định xem thực thi có bao giờ thực sự đến cuối hàm). Nó chỉ đơn giản là undefined điều gì sẽ xảy ra nếu điều này xảy ra. Nó có thể xuất hiện để làm việc (bởi vì chức năng gọi điện thoại sẽ chỉ xem xét bất kỳ giá trị rác thải là ở vị trí mà giá trị trả về được cho là), nó có thể sụp đổ, hoặc làm cho con quỷ bay ra khỏi mũi của bạn.

+3

Cảm ơn bạn đã giải thích tại sao nó không phải là lỗi biên dịch để không có câu lệnh trả về rõ ràng chức năng :) – ajay

2

Mặc dù trình biên dịch aC++ không thể luôn luôn phát hiện khi một hàm không thể thực hiện câu lệnh trả về, nó thường là có thể.

Về mặt tươi sáng, ít nhất g ++ giúp dễ dàng phát hiện bằng tùy chọn trình biên dịch dòng lệnh "-Bỏ lại kiểu". Bạn chỉ cần nhớ để kích hoạt nó. (Nó cũng được kích hoạt nếu bạn sử dụng "-Wall".)

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