2010-01-26 7 views
55

tôi đang tìm kiếm tại một số ví dụ C++ mã cho một giao diện phần cứng Tôi đang làm việc với và nhận thấy rất nhiều báo cáo dọc theo dòng sau đây:Lý do đằng sau việc đặt các hằng số trong các câu lệnh if là gì?

if (NULL == pMsg) return rv; 

Tôi chắc rằng tôi đã nghe người ta nói rằng việc đưa các liên tục đầu tiên là một ý tưởng hay, nhưng tại sao lại như vậy? Là nó chỉ để nếu bạn có một tuyên bố lớn, bạn có thể nhanh chóng nhìn thấy những gì bạn đang so sánh với hoặc là có nhiều hơn với nó?

+4

1 cho một tiêu đề câu hỏi thực sự tốt . – OregonGhost

+1

khá chắc chắn tôi đã nhìn thấy câu hỏi này nhiều hơn một lần, không thể tìm thấy nó ngay bây giờ mặc dù. –

+1

@ Idan: Tôi đã ngạc nhiên vì tôi không thể tìm thấy nó, nhưng sau 5 phút tìm kiếm tôi đã từ bỏ ;-) –

Trả lời

76

Vì vậy, bạn không trộn so sánh (==) với bài tập (=).

Như bạn biết, bạn không thể gán cho hằng số. Nếu bạn thử, trình thông báo sẽ cho bạn một lỗi.

Về cơ bản, đó là một trong các kỹ thuật lập trình phòng thủ. Để bảo vệ bản thân khỏi chính mình.

+2

Rực rỡ - cảm ơn rất nhiều :-) –

7

Khi hằng số là lần đầu tiên, trình biên dịch sẽ cảnh báo bạn nếu bạn vô tình viết = thay vì == vì việc gán giá trị cho hằng số là bất hợp pháp.

29

Để ngăn chặn bạn từ viết:

if (pMsg = NULL) return rv; 

do nhầm lẫn. Một trình biên dịch tốt sẽ cảnh báo bạn về điều này tuy nhiên, vì vậy hầu hết mọi người không sử dụng cách "đầu tiên không đổi", vì họ thấy khó đọc.

+0

+1 sau khi chỉnh sửa ninja của bạn. –

+8

+1 vì đã đề cập rằng các trình biên dịch hiện đại cảnh báo về điều này. Một lý do khác để không làm điều đó trong C++ là tránh những cạm bẫy với quá tải toán tử kém. ('_bstr_t', oh, làm sao tôi ghét bạn.) – jamesdlin

+0

+1 để đề cập đến các vấn đề về khả năng đọc/bảo trì. – Ben

8

Nó dừng lỗi gán = đơn.

Ví dụ,

if (NULL = pMsg) return rv; 

sẽ không biên dịch, nơi như

if (pMsg = NULL) return rv; 

sẽ biên soạn và cung cấp cho bạn đau đầu

2

Họ nói, "để ngăn chặn pha trộn của phân và so sánh".

Trên thực tế tôi nghĩ rằng nó là vô nghĩa: nếu bạn là nên xử lý kỷ luật mà bạn đừng quên đặt liên tục ở phía bên trái, bạn chắc chắn sẽ không trộn lên '=' với '==' , phải không? ;)

+0

Không, nhưng, bạn có nhiều cơ hội tránh nhầm lẫn với thứ gì đó nhiều lần nhấn phím nhiều lần có thể gây ra do không nhập đủ mạnh để nhận lệnh thứ hai =. Do đó, bạn biết đấy, lỗi đánh máy. –

+0

Tôi chỉ tò mò làm thế nào bạn đã thường xuyên làm như vậy đánh máy? Đặt cược bạn đã không. –

+6

Tôi muốn nghĩ rằng tôi khá kỷ luật, nhưng bất kể phong cách mã hóa của bạn, mọi người làm cho lỗi đánh máy thường xuyên và thói quen đơn giản này tránh được những sai lầm như vậy khiến cho việc thực thi. Một lỗi bắt tại thời gian biên dịch là giá trị 10 tại thời điểm thực hiện :-) –

2

Trình biên dịch xuất cảnh báo là tốt, nhưng một số người trong chúng ta trong thế giới thực không thể đủ khả năng để coi cảnh báo là lỗi. Đảo ngược thứ tự biến và hằng số có nghĩa là phiếu đơn giản này luôn xuất hiện dưới dạng lỗi và ngăn biên dịch. Bạn đã quen với mô hình này rất nhanh chóng, và lỗi mà nó bảo vệ chống lại là một hình thức tinh tế, vốn thường khó tìm thấy khi được giới thiệu.

8

Để làm rõ những gì tôi đã viết trong một số nhận xét, đây là lý do không để thực hiện việc này trong mã C++.

Có người viết, nói, một lớp chuỗi và quyết định thêm một nhà điều hành đúc để const char*:

class BadString 
{ 
public: 
    BadString(const char* s) : mStr(s) { } 

    operator const char*() const { return mStr.c_str(); } 

    bool operator==(const BadString& s) { return mStr == s.mStr; } 

    // Other stuff... 

private: 
    std::string mStr; 
}; 

Bây giờ một người nào đó một cách mù quáng áp dụng mô hình constant == variable lập trình "phòng thủ":

BadString s("foo"); 

if ("foo" == s) // Oops. This compares pointers and is never true. 
{ 
    // ... 
} 

Đây là , IMO, một vấn đề xảo quyệt hơn là phân công ngẫu nhiên bởi vì bạn không thể nói từ trang web cuộc gọi rằng bất kỳ điều gì rõ ràng là sai.

Tất nhiên, những bài học thực là:

  1. Đừng viết lớp chuỗi của riêng bạn.
  2. Tránh các toán tử ẩn ngầm, đặc biệt là khi thực hiện (1).

Nhưng đôi khi bạn đang xử lý các API của bên thứ ba mà bạn không thể kiểm soát. Ví dụ, lớp chuỗi _bstr_t phổ biến trong lập trình Windows COM bị lỗ hổng này.

+0

Tôi đã nhìn thấy rất nhiều nơi cấm quá tải toán tử nói chung. Yay C++. –

+0

Chẳng phải s == "foo" có cùng vấn đề không? –

+0

@Jon Cage: Không. Vô tình, trong khi '" foo "== s' không kích hoạt lỗi mơ hồ mong muốn,' s == "foo" 'thực hiện. (Tác giả sau đó có thể thực thi 'bool MyString :: operator == (const char *) const' sẽ giải quyết sự không rõ ràng' s == "foo" 'nhưng vẫn không làm gì để sửa' "foo" == s'.) – jamesdlin

0

tôi quên bài báo, nhưng báo giá đi một cái gì đó như: "Rõ ràng nó dễ dàng hơn ghi nhớ để đặt hằng số đầu tiên, hơn nó được ghi nhớ để sử dụng ==";))