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 boolean
loại thực tế (và giải quyết true
và 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 __cplusplus
macro) và thực sự sử dụng true
và false
.
Trong một trình biên dịch C, điều này tương đương với 0
và 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==1
là một int
. (xem stackoverflow.com/questions/7687403/ khăn .)
boolean
loại?
true
hoặc false
.
#define TRUE true
và #define FALSE false
bấ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 TRUE
và FALSE
khô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á 1
và (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 TRUE
và FALSE
theo 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 FALSE
như 0
và TRUE
như -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à FALSE
và mọi giá trị khác không được hiểu là TRUE
, bạn không bao giờTRUE
FALSE
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 int
s là bool
s. 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 TRUE
chỉ 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) == TRUE
sau đó a > b
nhưng ngụ ý ngược lại có thể không giữ.
(1==1)
và 1
cả hai biểu thức không đổi int
có 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 TRUE
theo 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 == 1
có ý nghĩa chính xác như 1
; và 1 == 0
có cùng ý nghĩa như 0
. Tuy nhiên, trong các đơn vị dịch C ++, 1 == 1
có loại bool
. Vì vậy, TRUE
macro 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 foo
có quá tải cho int
và bool
sau đó, thì foo(TRUE)
sẽ chọn bool
quá tải. Nếu TRUE
chỉ được định nghĩa là 1
, thì nó sẽ không hoạt động tốt trong C ++. foo(TRUE)
sẽ muốn int
quá tải.
Tất nhiên, C99 giới thiệu bool
, true
và false
và 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:
TRUE
và FALSE
như (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
, false
và bool
để thay thế.
#ifndef __cplusplus
typedef int bool;
#define true (0==0)
#define false (!true)
#endif
Điều đó đang được nói, 0==0
mẹ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 true
hằng số được bool
biê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 bool
tham 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.
bool
và int
khô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à 0
hoặc 1
. 1==1
được đảm bảo để được đánh giá 1
và !(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ữ TRUE
và FALSE
macro:
Đối với C,
TRUE
nê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!0
chơi an toàn.
Cũng trong C99, các stdbool.h
định nghĩa cho macro boolean true
và 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á false
và 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á 1
và 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ị 0
hoặ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.
_Bool
và <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 TRUE
và FALSE
là 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)