2009-02-17 89 views
12

Sau khi lập trình trong C trong nhiều năm, tôi nhận ra rằng tôi đã bỏ qua quy ước C về việc trả về số không từ một hàm để biểu thị thành công. Công ước có vẻ sai trái về mặt ngữ nghĩa đối với tôi, vì không phải tất nhiên là sai. Vấn đề là tôi muốn đặt tên cho các chức năng như is_valid_foobar(), và để chứa các quy ước của 'có nghĩa là sai thành công', tôi sẽ phải mơ hồ hơn ... đó là thay vì:Tôi có nên trả về giá trị TRUE/FALSE từ một hàm C không?

if (! is_valid_foobar()) { 
    return (error); 
} 

lập trình khác viết:

if (validate_foobar()) { 
    return (error); 
} 

Và thực hiện của tôi trông giống như:

int is_valid_foobar (int foobar) { 
    if (foobar < MAX_ALLOWED) { 
      return TRUE; 
     } 
     return FALSE; 
} 

tôi đã không thực sự bắt bất cứ pháo phòng không cho điều này trong mã số nhận xét. Vì vậy, tôi nghĩ rằng nó không phải là một thói quen khủng khiếp như vậy, nhưng nó là 'độc đáo'. Tôi tò mò những gì mọi người nghĩ.

Tôi rất cẩn thận về các lựa chọn tôi thực hiện cho chức năng và tên biến, và bình luận đánh giá điển hình là "mã thực sự rõ ràng", và hơn nữa nó không làm phiền tôi chút nào phải gõ thêm ! ở phía trước của cuộc gọi chức năng. Nhưng những gì nói lên, những người hùng mạnh của S.O?

Trả lời

19

Tôi muốn nói cả hai đều đúng, cho các mục đích khác nhau:

Nếu bạn đang thực hiện xác thực đi/không đi đơn giản, ví dụ: is_numeric(), sau đó đúng và sai công việc độc đáo.

Đối với một cái gì đó phức tạp hơn, mô hình thành công 0 == là hữu ích ở chỗ nó cho phép nhiều hơn một điều kiện lỗi được trả về.

Trong trường hợp này, người gọi có thể chỉ cần kiểm tra theo 0 hoặc kiểm tra trả về không phải 0 để có giải thích cụ thể hơn về lỗi. ví dụ. cuộc gọi mở tệp có thể không thành công do không tồn tại, không đủ quyền, v.v.

+0

Quyền - và nếu bạn không thích trực tiếp sử dụng 0 để thành công, thì thường khung hoặc nền tảng cung cấp một cái gì đó giống như một giá trị/giá trị ERROR_SUCCESS (hoặc tên thú vị) (cùng với tên mã lỗi tương ứng) để trừu tượng ra khỏi số giá trị phần nào. –

+0

Cách sử dụng này cũng cho phép xây dựng "if (int e = foo()) {/ * xử lý lỗi * /};", có thể trông rất khó khăn đối với những người được nêu trên nhiều ngôn ngữ có tính năng hơn, nhưng sạch sẽ và gọn gàng theo tiêu chuẩn c. – dmckee

3

Tôi không chắc chắn rằng tôi đồng ý rằng có một quy ước "trả về số không từ một hàm để biểu thị thành công".

AFAIK, quy ước là số không là false và tất cả các nonzeros đều đúng trong trường hợp các biến vị ngữ.

Tuy nhiên, quy ước này chỉ nên áp dụng cho các biến vị ngữ hiển nhiên trả về các boolean (ví dụ: true/false). Nếu mục tiêu chính của hàm không trả về giá trị boolean (ví dụ, printf, fopen, v.v.), thì giá trị trả về được sử dụng để chỉ ra các lý do lỗi, và sau đó bạn có thể áp dụng quy ước UNIX là "im lặng hoặc 0 trừ khi Có vấn đề".

Đối với các giá trị trả lại, không có gì sai khi sử dụng các giá trị trả về cố định, nó làm cho mọi thứ thuận tiện hơn.

Nguy cơ lớn, IMHO, là nhiều người khai báo hằng số của chính họ và khi người khác sử dụng cùng một tệp, bạn bắt đầu chạy vào xung đột với các hằng số của riêng họ. Vì vậy, TRUE/FALSE và xung đột với TRUE/FALSE của người khác xuống dòng.

2

Đó không phải là quá nhiều quy ước C dưới dạng vỏ UN * X. Hãy xem xét các hàm chuẩn C iasalpha(), isdigit() v.v. Tất cả đều trở lại khác 0 để chỉ ra thành công. Điểm mấu chốt: trong C 'true' là khác không.

+0

+1.Ngoài ra, trong Unix/Linux, các quy ước này áp dụng cho các chương trình (các tiến trình riêng biệt) gọi và đường ống cho nhau, không hoàn toàn giống với chức năng gọi nhau trong một chương trình, mặc dù quy ước là như nhau. – heltonbiker

11

Quy ước không chính xác như bạn nghĩ.Các quy trình phải thoát với trạng thái 0 để biểu thị thành công và các hàm trả về mã lỗi thường sẽ sử dụng 0 để biểu thị "không có lỗi". Nhưng như là một boolean, 0 nên có nghĩa là sai và nonzero nên có nghĩa là đúng sự thật. Để sử dụng 0 cho boolean đúng sẽ giúp bạn có được trên The Daily WTF một ngày nào đó.

3

Đặc biệt khi bạn đặt tên hàm is_foo(), hàm ký tự C chuẩn (isdigit(), isupper(), v.v) là tiền lệ tốt để thực hiện theo cách của bạn.

3

C không có khái niệm về boolean khác 0 là sai và bất kỳ điều gì khác là đúng.

Ý tưởng trả về 0 xuất phát từ việc có mã trả về cho biết lỗi là gì. Nếu bạn không làm mã trả về, thì không có gì sai khi xử lý 1 và 0 là đúng và sai. Sau cùng, TRUE và FALSE chỉ là typedef cho 1 và 0 trong C.

Điều này phải được ghi lại rõ ràng và nhận xét chức năng của bạn nên nói rõ "Trả về TRUE hoặc FALSE".

Bạn cũng có thể viết nếu (is_invalid_foobar()), có thể làm cho câu lệnh dễ hiểu và vẫn chính xác về mặt ngữ nghĩa.

0

Nó chỉ tệ nếu nó đốt cháy bạn. Nếu bạn không bao giờ theo dõi bất kỳ lỗi nào cho điều này, tôi muốn nói rằng bạn là OK. Điều quan trọng hơn, là bình luận ở trên hàm bắt đầu bằng, "Trả về số không cho ..."

Quy ước "không phải là lỗi" được sử dụng khi cố gắng nói lý do tại sao cùng với cờ lỗi.

6

Nó được một lúc kể từ khi tôi lập trình C, nhưng tôi nghĩ rằng bạn đang nói về hai loại khác nhau của các chức năng ở đây:

  • is_foo là một chức năng để kiểm tra đối với một số foo tài sản và trả 0 (false) hoặc không phải 0 (true) để chỉ ra giá trị boolean của thuộc tính đó. Khi gọi các hàm đó, không có trạng thái lỗi nào được mong đợi (và nếu nó xảy ra, nó được ánh xạ trên một trong các giá trị đó).
  • foo là một hàm thực hiện tác vụ foo. Nó trả về 0 về thành công và giá trị không phải là 0 do lỗi.
0

với tôi, thực sự kiểm tra đối với 0 có vẻ tự nhiên hơn và trình biên dịch tối ưu hóa nó anyway vì vậy tôi muốn viết ví dụ

if (check_foo == 0) // do something

0

Return giá trị theo hàm - quy ước cho Đúng và Sai HOẶC Thành công và Lỗi:

  1. Một API, vv hiển thị thành công với giá trị trả về 0 và giá trị trả về = giá trị lỗi khác 0.
  2. Nếu có điều gì đó đúng; các hàm trả về 1. Ví dụ: isStackEmpty() sẽ trả về 1 nếu ngăn xếp trống.
0

Vẫn hoàn toàn tùy ý trả về 1 hoặc 0. Chỉ cần nhất quán và nếu có mã lỗi, ít nhất hãy nhận xét ý nghĩa của chúng ở đâu đó.

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