Tôi đã thấy định nghĩa trong C
#define TRUE (1==1)
#define FALSE (!TRUE)
Điều này có cần thiết không? Lợi ích gì khi chỉ đơn giản là xác định TRUE là 1 và FALSE là 0?
Tôi đã thấy định nghĩa trong C
#define TRUE (1==1)
#define FALSE (!TRUE)
Điều này có cần thiết không? Lợi ích gì khi chỉ đơn giản là xác định TRUE là 1 và FALSE là 0?
Câu trả lời:
Cách tiếp cận này sẽ sử dụng booleanloại thực tế (và giải quyết truevà false) nếu trình biên dịch hỗ trợ nó. (cụ thể là C ++)
Tuy nhiên, sẽ tốt hơn nếu kiểm tra xem C ++ có được sử dụng hay không (thông qua __cplusplusmacro) và thực sự sử dụng truevà false.
Trong một trình biên dịch C, điều này tương đương với 0và 1.
(lưu ý rằng việc xóa dấu ngoặc đơn sẽ phá vỡ điều đó do thứ tự các thao tác)
1==1là một int. (xem stackoverflow.com/questions/7687403/ khăn .)
booleanloại?
truehoặc false.
#define TRUE truevà #define FALSE falsebất cứ khi nào __cplusplusđược xác định.
Câu trả lời là tính di động. Các giá trị số của TRUEvà FALSEkhông quan trọng. Có gì là quan trọng là một tuyên bố như if (1 < 2)đánh giá lại để if (TRUE)và một tuyên bố như if (1 > 2)đánh giá lại để if (FALSE).
Cấp, trong C, (1 < 2)đánh giá 1và (1 > 2)đánh giá 0, như những người khác đã nói, không có sự khác biệt thực tế nào liên quan đến trình biên dịch. Nhưng bằng cách để trình biên dịch xác định TRUEvà FALSEtheo quy tắc riêng của mình, bạn sẽ làm cho ý nghĩa của chúng rõ ràng với các lập trình viên và bạn đảm bảo tính nhất quán trong chương trình của bạn và bất kỳ thư viện nào khác (giả sử thư viện khác tuân theo tiêu chuẩn C ... bạn kinh ngạc).
Một số Lịch sử
Một số vấn đề cơ bản được xác định FALSEnhư 0và TRUEnhư -1. Giống như nhiều ngôn ngữ hiện đại, họ giải thích bất kỳ giá trị khác không là TRUE, nhưng họ đã đánh giá các biểu thức boolean là đúng -1. Hoạt NOTđộng của họ được thực hiện bằng cách thêm 1 và lật ký hiệu, bởi vì nó hiệu quả để làm theo cách đó. Thế là 'KHÔNG x' trở thành -(x+1). Một tác dụng phụ của điều này là một giá trị như 5đánh giá TRUE, nhưng cũng NOT 5đánh giá -6, đó cũng là TRUE! Tìm loại lỗi này không vui.
Thực tiễn tốt nhất
Đưa ra các quy tắc thực tế rằng số 0 được hiểu là FALSEvà mọi giá trị khác không được hiểu là TRUE, bạn không bao giờTRUEFALSE nên so sánh các biểu thức trông giống boolean với hoặc . Ví dụ:
if (thisValue == FALSE) // Don't do this!
if (thatValue == TRUE) // Or this!
if (otherValue != TRUE) // Whatever you do, don't do this!
Tại sao? Bởi vì nhiều lập trình viên sử dụng phím tắt coi ints là bools. Chúng không giống nhau, nhưng trình biên dịch thường cho phép nó. Vì vậy, ví dụ, nó hoàn toàn hợp pháp để viết
if (strcmp(yourString, myString) == TRUE) // Wrong!!!
Điều đó có vẻ hợp pháp và trình biên dịch sẽ vui vẻ chấp nhận nó, nhưng có lẽ nó không làm những gì bạn muốn. Đó là bởi vì giá trị trả về strcmp()là
0 nếu yourString == myString
<0 nếu yourString < myString
> 0 nếuyourString > myString
Vì vậy, dòng trên TRUEchỉ trả về khi yourString > myString.
Cách đúng để làm điều này là một trong hai
// Valid, but still treats int as bool.
if (strcmp(yourString, myString))
hoặc là
// Better: lingustically clear, compiler will optimize.
if (strcmp(yourString, myString) != 0)
Tương tự:
if (someBoolValue == FALSE) // Redundant.
if (!someBoolValue) // Better.
return (x > 0) ? TRUE : FALSE; // You're fired.
return (x > 0); // Simpler, clearer, correct.
if (ptr == NULL) // Perfect: compares pointers.
if (!ptr) // Sleazy, but short and valid.
if (ptr == FALSE) // Whatisthisidonteven.
Bạn sẽ thường tìm thấy một số "ví dụ xấu" trong mã sản xuất và nhiều lập trình viên có kinh nghiệm đã thề với họ: họ làm việc, một số ngắn hơn các lựa chọn chính xác (về mặt giáo dục?), Và các thành ngữ gần như được công nhận. Nhưng hãy xem xét: các phiên bản "đúng" không kém hiệu quả, chúng được đảm bảo là có thể mang theo được, chúng sẽ vượt qua cả những người nghiêm ngặt nhất và ngay cả những lập trình viên mới cũng sẽ hiểu chúng.
Điều đó có đáng không?
(1==1)không di động hơn 1. Các quy tắc riêng của nhà soạn nhạc là các quy tắc của ngôn ngữ C, rõ ràng và không mơ hồ về ngữ nghĩa của các toán tử đẳng thức và quan hệ. Tôi chưa bao giờ thấy một trình biên dịch có được những thứ này sai.
strcmpđược biết là nhỏ hơn, bằng hoặc lớn hơn 0. Nó không được đảm bảo là -1, 0 hoặc 1 và có các nền tảng trong tự nhiên không trả lại các giá trị đó để đạt được tốc độ thực hiện. Vì vậy, nếu strcmp(a, b) == TRUEsau đó a > bnhưng ngụ ý ngược lại có thể không giữ.
(1==1)và 1cả hai biểu thức không đổi intcó giá trị 1. Chúng giống hệt nhau về mặt ngữ nghĩa. Tôi cho rằng bạn có thể viết mã phục vụ cho những độc giả không biết điều đó, nhưng nó kết thúc ở đâu?
Thủ (1 == 1)thuật này rất hữu ích để xác định TRUEtheo cách trong suốt đối với C, nhưng cung cấp cách gõ tốt hơn trong C ++. Mã tương tự có thể được hiểu là C hoặc C ++ nếu bạn đang viết bằng một phương ngữ gọi là "Clean C" (biên dịch thành C hoặc C ++) hoặc nếu bạn đang viết các tệp tiêu đề API có thể được sử dụng bởi các lập trình viên C hoặc C ++.
Trong các đơn vị dịch C, 1 == 1có ý nghĩa chính xác như 1; và 1 == 0có cùng ý nghĩa như 0. Tuy nhiên, trong các đơn vị dịch C ++, 1 == 1có loại bool. Vì vậy, TRUEmacro xác định theo cách đó tích hợp tốt hơn vào C ++.
Một ví dụ về cách nó tích hợp tốt hơn là ví dụ nếu hàm foocó quá tải cho intvà boolsau đó, thì foo(TRUE)sẽ chọn boolquá tải. Nếu TRUEchỉ được định nghĩa là 1, thì nó sẽ không hoạt động tốt trong C ++. foo(TRUE)sẽ muốn intquá tải.
Tất nhiên, C99 giới thiệu bool, truevà falsevà chúng có thể được sử dụng trong các tập tin tiêu đề mà làm việc với C99 và với C.
Tuy nhiên:
TRUEvà FALSEnhư (0==0)và (1==0)trước C99.Nếu bạn đang làm việc trong một C hỗn hợp và dự án C ++, và không muốn C99, xác định các chữ thường true, falsevà boolđể thay thế.
#ifndef __cplusplus
typedef int bool;
#define true (0==0)
#define false (!true)
#endif
Điều đó đang được nói, 0==0mẹo là (được?) Được sử dụng bởi một số lập trình viên ngay cả trong mã không bao giờ có ý định tương tác với C ++ theo bất kỳ cách nào. Điều đó không mua bất cứ thứ gì và gợi ý rằng lập trình viên có sự hiểu lầm về cách thức hoạt động của booleans trong C.
Trong trường hợp giải thích C ++ không rõ ràng, đây là một chương trình thử nghiệm:
#include <cstdio>
void foo(bool x)
{
std::puts("bool");
}
void foo(int x)
{
std::puts("int");
}
int main()
{
foo(1 == 1);
foo(1);
return 0;
}
Đầu ra:
bool
int
Đối với câu hỏi từ các ý kiến về cách các hàm C ++ bị quá tải có liên quan đến lập trình C và C ++ hỗn hợp. Đây chỉ là minh họa một sự khác biệt loại. Một lý do hợp lệ cho việc muốn một truehằng số được boolbiên dịch thành C ++ là để chẩn đoán sạch. Ở các mức cảnh báo cao nhất, trình biên dịch C ++ có thể cảnh báo chúng ta về chuyển đổi nếu chúng ta chuyển một số nguyên dưới dạng booltham số. Một lý do để viết trong Clean C không chỉ là mã của chúng tôi dễ mang theo hơn (vì nó được hiểu bởi trình biên dịch C ++, không chỉ trình biên dịch C), mà chúng ta có thể hưởng lợi từ ý kiến chẩn đoán của trình biên dịch C ++.
TRUEý chí sẽ khác nhau theo C ++.
#ifdef __cplusplusđể thể hiện ý định của mình rõ ràng hơn nhiều.
boolvà intkhông quan trọng trong thực tế, vì chúng hoàn toàn có thể chuyển đổi lẫn nhau (và trong C thực sự "giống nhau" , lưu ý các trích dẫn , mặc dù) và không có nhiều tình huống mà bạn thực sự cần phải phân biệt giữa hai. "không nhiều" có lẽ là quá nặng, "ít hơn nhiều so với mã sử dụng các mẫu và quá tải" có lẽ sẽ tốt hơn.
#define TRUE (1==1)
#define FALSE (!TRUE)
tương đương với
#define TRUE 1
#define FALSE 0
trong C.
Kết quả của các toán tử quan hệ là 0hoặc 1. 1==1được đảm bảo để được đánh giá 1và !(1==1)được đảm bảo để được đánh giá 0.
Hoàn toàn không có lý do để sử dụng mẫu đầu tiên. Lưu ý rằng biểu mẫu đầu tiên tuy nhiên không kém hiệu quả vì trên hầu hết các trình biên dịch, một biểu thức hằng được đánh giá tại thời gian biên dịch thay vì tại thời gian chạy. Điều này được cho phép theo quy tắc này:
(C99, 6.6p2) "Một biểu thức hằng có thể được đánh giá trong quá trình dịch thay vì thời gian chạy và do đó có thể được sử dụng ở bất kỳ nơi nào có thể có hằng số."
PC-Lint thậm chí sẽ phát hành một thông báo (506, boolean giá trị không đổi) nếu bạn không sử dụng một chữ TRUEvà FALSEmacro:
Đối với C,
TRUEnên được xác định là1. Tuy nhiên, các ngôn ngữ khác sử dụng số lượng khác 1, vì vậy một số lập trình viên cảm thấy rằng!0chơi an toàn.
Cũng trong C99, các stdbool.hđịnh nghĩa cho macro boolean truevà false sử dụng trực tiếp bằng chữ:
#define true 1
#define false 0
1==1được đảm bảo để được đánh giá1
if(foo == true), sẽ đi từ thực tiễn xấu đến lỗi thẳng.
(x == TRUE)có thể có giá trị thật khác hơn x.
Ngoài C ++ (đã được đề cập), một lợi ích khác là cho các công cụ phân tích tĩnh. Trình biên dịch sẽ loại bỏ bất kỳ sự thiếu hiệu quả nào, nhưng một bộ phân tích tĩnh có thể sử dụng các loại trừu tượng của riêng nó để phân biệt giữa các kết quả so sánh và các loại số nguyên khác, do đó, nó biết rằng TRUE phải là kết quả của một so sánh và không nên được coi là tương thích với một số nguyên.
Rõ ràng C nói rằng chúng tương thích, nhưng bạn có thể chọn cấm sử dụng tính năng đó một cách có chủ ý để giúp làm nổi bật các lỗi - ví dụ, trong đó ai đó có thể nhầm lẫn &và &&, hoặc họ đã làm hỏng ưu tiên nhà điều hành của họ.
if (boolean_var == TRUE) bằng cách mở rộng if (boolean_var == (1 == 1))nhờ vào thông tin loại nâng cao của (1 == 1)nút rơi vào mẫu if (<*> == <boolean_expr>).
Sự khác biệt pratical là không có. 0được đánh giá falsevà 1được đánh giá true. Thực tế là bạn sử dụng biểu thức boolean ( 1 == 1) hoặc 1, để xác định true, sẽ không tạo ra bất kỳ sự khác biệt nào. Cả hai đều được đánh giá int.
Lưu ý rằng thư viện chuẩn C cung cấp một tiêu đề cụ thể để xác định booleans : stdbool.h.
trueđược đánh giá 1và falseđược đánh giá 0. C không biết về các kiểu boolean bản địa, chúng chỉ là số nguyên.
int, với giá trị 0hoặc 1. C có một kiểu boolean thực tế ( _Bool, với một macro boolđược định nghĩa trong <stdbool.h>, nhưng nó chỉ được thêm vào trong C99, không thay đổi ngữ nghĩa của các toán tử để sử dụng loại mới.
_Boolvà <stdbool.h>có #define bool _Bool.
1 == 1được đánh giá là int. Đã chỉnh sửa.
Chúng tôi không biết giá trị chính xác mà TRUE bằng và trình biên dịch có thể có định nghĩa riêng. Vì vậy, những gì bạn có quyền riêng tư là sử dụng nội bộ của trình biên dịch để định nghĩa. Điều này không phải lúc nào cũng cần thiết nếu bạn có thói quen lập trình tốt nhưng có thể tránh được các vấn đề đối với một số kiểu mã hóa xấu, ví dụ:
if ((a> b) == TRUE)
Đây có thể là một thảm họa nếu bạn xác định thủ công TRUE là 1, trong khi giá trị bên trong của TRUE là một giá trị khác.
>toán tử luôn mang lại 1 cho true, 0 cho false. Không có khả năng bất kỳ trình biên dịch C nào bị lỗi này. So sánh bình đẳng TRUEvà FALSElà phong cách kém; ở trên được viết rõ ràng hơn như if (a > b). Nhưng ý tưởng rằng các trình biên dịch C khác nhau có thể đối xử với sự thật và sai khác nhau chỉ là không chính xác.
Thông thường trong Ngôn ngữ lập trình C, 1 được định nghĩa là đúng và 0 được định nghĩa là sai. Do đó tại sao bạn thấy sau đây khá thường xuyên:
#define TRUE 1
#define FALSE 0
Tuy nhiên, bất kỳ số nào không bằng 0 cũng sẽ được đánh giá là đúng trong một tuyên bố có điều kiện. Do đó bằng cách sử dụng dưới đây:
#define TRUE (1==1)
#define FALSE (!TRUE)
Bạn chỉ có thể chỉ ra một cách rõ ràng rằng bạn đang cố gắng chơi nó an toàn bằng cách làm sai bằng với bất cứ điều gì không đúng.
#define TRUE (’/’/’/’);#define FALSE (’-’-’-’)(được lấy từ mã hóa-guiances.com/cbook/cbook1_1.pdf trang 871)