C không có bất kỳ loại boolean tích hợp nào. Cách tốt nhất để sử dụng chúng trong C là gì?
C không có bất kỳ loại boolean tích hợp nào. Cách tốt nhất để sử dụng chúng trong C là gì?
Câu trả lời:
Từ tốt nhất đến tồi tệ hơn:
Tùy chọn 1 (C99)
#include <stdbool.h>
Lựa chọn 2
typedef enum { false, true } bool;
Lựa chọn 3
typedef int bool;
enum { false, true };
Lựa chọn 4
typedef int bool;
#define true 1
#define false 0
Nếu bạn chưa quyết định, hãy đi với # 1!
<stdbool.h>
bool
trình biên dịch chọn có thể phù hợp hơn cho mục đích dự định của giá trị boolean hơn là sử dụng một int
(tức là trình biên dịch có thể chọn thực hiện bool
khác với một int
). Nó cũng có thể dẫn đến việc kiểm tra loại chặt chẽ hơn vào thời gian biên dịch, nếu bạn may mắn.
int
cho bool
? Điều đó thật lãng phí. Sử dụng unsigned char
. Hoặc sử dụng được xây dựng trong C _Bool
.
Một vài suy nghĩ về booleans trong C:
Tôi đã đủ tuổi để tôi chỉ sử dụng int
s đơn giản làm kiểu boolean của mình mà không có bất kỳ typedefs hoặc định nghĩa đặc biệt hoặc enum nào cho các giá trị đúng / sai. Nếu bạn làm theo đề xuất của tôi dưới đây về việc không bao giờ so sánh với các hằng số boolean, thì bạn chỉ cần sử dụng 0/1 để khởi tạo các cờ. Tuy nhiên, cách tiếp cận như vậy có thể được coi là quá phản động trong thời hiện đại này. Trong trường hợp đó, người ta chắc chắn nên sử dụng <stdbool.h>
vì ít nhất nó có lợi ích của việc được tiêu chuẩn hóa.
Dù các hằng số boolean được gọi là gì, chỉ sử dụng chúng để khởi tạo. Không bao giờ viết một cái gì đó như
if (ready == TRUE) ...
while (empty == FALSE) ...
Chúng luôn có thể được thay thế bởi rõ ràng hơn
if (ready) ...
while (!empty) ...
Lưu ý rằng những điều này thực sự có thể hợp lý và dễ hiểu được đọc thành tiếng.
Đặt tên biến boolean của bạn tên tích cực, tức là full
thay vì notfull
. Cái sau dẫn đến mã khó đọc dễ dàng. Đối chiếu
if (full) ...
if (!full) ...
với
if (!notfull) ...
if (notfull) ...
Cả hai cặp trước đây đọc tự nhiên, trong khi !notfull
rất khó đọc ngay cả khi nó, và trở nên tồi tệ hơn nhiều trong các biểu thức boolean phức tạp hơn.
Đối số Boolean thường nên tránh. Hãy xem xét một hàm được định nghĩa như thế này
void foo(bool option) { ... }
Trong phần thân của hàm, rất rõ ràng đối số có nghĩa là gì vì nó có một tên thuận tiện và hy vọng có ý nghĩa. Nhưng, các trang web cuộc gọi trông giống như
foo(TRUE);
foo(FALSE):
Ở đây, về cơ bản không thể nói tham số có nghĩa là gì mà không luôn luôn nhìn vào định nghĩa hoặc khai báo hàm và nó sẽ trở nên tồi tệ hơn ngay khi bạn thêm các tham số boolean thậm chí nhiều hơn. Tôi đề nghị một trong hai
typedef enum { OPT_ON, OPT_OFF } foo_option;
void foo(foo_option option);
hoặc là
#define OPT_ON true
#define OPT_OFF false
void foo(bool option) { ... }
Trong cả hai trường hợp, trang web cuộc gọi bây giờ trông giống như
foo(OPT_ON);
foo(OPT_OFF);
mà người đọc có ít nhất một cơ hội để hiểu mà không cần nạo vét định nghĩa foo
.
a == b
làm việc?
a
và b
tính từ 0, tôi khuyên bạn nên a > 0 == b > 0
thay thế. Nếu bạn khăng khăng lợi dụng tính trung thực của các giá trị khác không tùy ý, !!var
sẽ mang lại giá trị 0/1 tương đương var
, vì vậy bạn có thể viết !!a == !!b
, mặc dù khá nhiều độc giả sẽ thấy khó hiểu.
!a == !b
cũng đủ để kiểm tra sự bằng nhau, các số không trở thành số không và số không trở thành số một.
!!a
là "chuyển đổi không boolean a thành giá trị thật tương đương của nó", trong khi tôi đọc !a
là "đảo ngược biến boolean a". Cụ thể, tôi tìm kiếm một số lý do cụ thể mà sự đảo ngược logic được mong muốn.
Một boolean trong C là một số nguyên: 0 cho false và khác không cho true.
Xem thêm Kiểu dữ liệu Boolean , phần C, C ++, Objective-C, AWK .
Đây là phiên bản mà tôi đã sử dụng:
typedef enum { false = 0, true = !false } bool;
Bởi vì false chỉ có một giá trị, nhưng một logic đúng có thể có nhiều giá trị, nhưng kỹ thuật đặt đúng là những gì trình biên dịch sẽ sử dụng cho ngược lại với false.
Điều này quan tâm đến vấn đề ai đó mã hóa thứ gì đó sẽ xảy ra:
if (true == !false)
Tôi nghĩ rằng tất cả chúng ta sẽ đồng ý rằng đó không phải là một thực tiễn tốt, nhưng với chi phí một lần để làm "đúng =! Sai", chúng tôi loại bỏ vấn đề đó.
[EDIT] Cuối cùng tôi đã sử dụng:
typedef enum { myfalse = 0, mytrue = !myfalse } mybool;
để tránh xung đột tên với các chương trình khác đã được xác định true
và false
. Nhưng khái niệm vẫn giữ nguyên.
[EDIT] Để hiển thị chuyển đổi số nguyên sang boolean:
mybool somebool;
int someint = 5;
somebool = !!someint;
Đầu tiên (đúng nhất)! chuyển đổi số nguyên khác không thành 0, sau đó là số thứ hai (hầu hết bên trái)! chuyển đổi 0 thành một myfalse
giá trị. Tôi sẽ để nó như một bài tập cho người đọc để chuyển đổi một số nguyên bằng không.
[EDIT] Phong cách của tôi là sử dụng cài đặt rõ ràng của một giá trị trong enum khi giá trị cụ thể được yêu cầu ngay cả khi giá trị mặc định sẽ giống nhau. Ví dụ: Bởi vì sai cần bằng 0 nên tôi sử dụng false = 0,
chứ không phảifalse,
true
, false
và bool
được làm nổi bật trong hầu hết các IDE vì họ là những giá trị enum và một typedef, như trái ngược với #defines
, đó là hiếm khi cú pháp tô sáng.
gcc -ansi -pedantic -Wall
không đưa ra cảnh báo, vì vậy tôi tin tưởng gcc
; Nếu điều này làm việc ngay cả cho c89
nó sẽ làm việc cho c99
aswell.
!
chỉ có thể trả về các giá trị 0
và 1
vì vậy true = !false
sẽ luôn gán giá trị 1. Phương thức này không cung cấp bất kỳ sự an toàn bổ sung nào typedef enum { false, true } bool;
.
if(!value)
), nhưng ngoại lệ đó không được áp dụng trong trường hợp cụ thể này.
Nếu bạn đang sử dụng trình biên dịch C99, nó có hỗ trợ tích hợp cho các loại bool:
#include <stdbool.h>
int main()
{
bool b = false;
b = true;
}
Điều đầu tiên đầu tiên. C, tức là ISO / IEC 9899 đã có kiểu boolean từ 19 năm nay . Đó là thời gian dài hơn thời gian dự kiến của sự nghiệp lập trình C với các phần nghiệp dư / học thuật / chuyên nghiệp kết hợp khi truy cập câu hỏi này . Của tôi không vượt qua điều đó có lẽ chỉ 1-2 năm. Điều đó có nghĩa là trong suốt thời gian mà một người đọc trung bình đã học được bất cứ điều gì về C, C thực sự đã có kiểu dữ liệu boolean .
Đối với kiểu dữ liệu #include <stdbool.h>
, và sử dụng true
, false
và bool
. Hoặc không bao gồm nó, và sử dụng _Bool
, 1
và 0
thay vào đó.
Có nhiều thực hành nguy hiểm khác nhau được thúc đẩy trong các câu trả lời khác cho chủ đề này. Tôi sẽ giải quyết chúng:
typedef int bool;
#define true 1
#define false 0
Điều này là không, bởi vì một người đọc bình thường - người đã học C trong vòng 19 năm đó - sẽ mong đợi điều đó bool
đề cập đến kiểu dữ liệu thực tế bool
và sẽ hành xử tương tự, nhưng không! Ví dụ
double a = ...;
bool b = a;
Với C99 bool
/ _Bool
, b
sẽ được đặt thành false
iff a
bằng 0 và true
ngược lại. C11 6.3.1.2p1
- Khi bất kỳ giá trị vô hướng nào được chuyển đổi thành
_Bool
, kết quả là 0 nếu giá trị so sánh bằng 0; mặt khác, kết quả là 1. 59)Chú thích
59) NaN không so sánh bằng 0 và do đó chuyển đổi thành 1.
Với typedef
vị trí, double
sẽ bị ép buộc thành một int
- nếu giá trị của số kép không nằm trong phạm vi cho int
, thì hành vi không được xác định .
Đương nhiên áp dụng tương tự cho nếu true
và false
được khai báo trong một enum
.
Điều thậm chí còn nguy hiểm hơn là tuyên bố
typedef enum bool {
false, true
} bool;
bởi vì bây giờ tất cả các giá trị ngoài 1 và 0 đều không hợp lệ và nếu giá trị đó được gán cho một biến của loại đó, thì hành vi sẽ hoàn toàn không được xác định .
Do đó, nếu bạn không thể sử dụng C99 vì một số lý do không thể giải thích được, đối với các biến boolean bạn nên sử dụng:
int
và các giá trị 0
và 1
nguyên trạng ; và cẩn thận thực hiện chuyển đổi tên miền từ bất kỳ giá trị nào khác sang giá trị này với phủ định kép!!
BOOL
, TRUE
và FALSE
!int
hoặc unsigned int
để liệt kê, nhưng tôi không biết gì trong Tiêu chuẩn sẽ khiến phép liệt kê hoạt động như bất kỳ thứ gì ngoài số nguyên kiểu.
typedef enum {
false = 0,
true
} t_bool;
!0 = 1
theo tiêu chuẩn C và !a = 0
với bất kỳ giá trị khác không nào của a
. Vấn đề là bất kỳ số không nào cũng được coi là đúng. Vì vậy, nếu a
và b
cả hai đều "đúng", thì không nhất thiết phải là `a == b`.
C có loại boolean: bool (ít nhất là trong 10 (!) Năm qua)
Bao gồm stdbool.h và true / false sẽ hoạt động như mong đợi.
bool
phải là một macro mở rộng _Bool
. Sự khác biệt quan trọng bởi vì bạn có thể #undef
một macro (và điều đó được cho phép, ít nhất là như một biện pháp chuyển tiếp), nhưng bạn không thể untypedef
là một typedef. Tuy nhiên, nó không làm thay đổi lực đẩy chính của bình luận đầu tiên của bạn.
Bất cứ điều gì khác không được đánh giá là đúng trong các hoạt động boolean, vì vậy bạn chỉ có thể
#define TRUE 1
#define FALSE 0
và sử dụng các hằng số.
Chỉ cần bổ sung cho các câu trả lời khác và một số làm rõ, nếu bạn được phép sử dụng C99.
+-------+----------------+-------------------------+--------------------+
| Name | Characteristic | Dependence in stdbool.h | Value |
+-------+----------------+-------------------------+--------------------+
| _Bool | Native type | Don't need header | |
+-------+----------------+-------------------------+--------------------+
| bool | Macro | Yes | Translate to _Bool |
+-------+----------------+-------------------------+--------------------+
| true | Macro | Yes | Translate to 1 |
+-------+----------------+-------------------------+--------------------+
| false | Macro | Yes | Translate to 0 |
+-------+----------------+-------------------------+--------------------+
Một số sở thích của tôi:
_Bool
hay bool
? Cả hai đều tốt, nhưng bool
trông tốt hơn so với từ khóa _Bool
.bool
và _Bool
là: false
hoặc true
. Chỉ định 0
hoặc 1
thay vì false
hoặc true
hợp lệ, nhưng khó đọc và hiểu luồng logic hơn.Một số thông tin từ tiêu chuẩn:
_Bool
là KHÔNG unsigned int
, nhưng là một phần của các kiểu số nguyên không dấu nhóm . Nó đủ lớn để giữ các giá trị 0
hoặc 1
.bool
true
và false
chắc chắn đó không phải là một ý tưởng tốt. Khả năng này được coi là lỗi thời và sẽ bị loại bỏ trong tương lai._Bool
hoặc bool
, nếu giá trị vô hướng bằng 0
hoặc so sánh với 0
nó 0
, nếu không, kết quả là 1
: _Bool x = 9;
9
được chuyển đổi thành 1
khi được gán cho x
._Bool
là 1 byte (8 bit), thông thường lập trình viên cố gắng sử dụng các bit khác, nhưng không được khuyến khích, vì điều duy nhất được đảm bảo là chỉ sử dụng một bit để lưu trữ dữ liệu, không giống như loại char
có 8 bit có sẵn.Bạn có thể sử dụng char, hoặc một container số nhỏ khác cho nó.
Mã giả
#define TRUE 1
#define FALSE 0
char bValue = TRUE;
int
), vì trên một số kiến trúc, bạn nhận được một hiệu suất đáng kể từ việc phải giải nén / mặt nạ kiểm tra các biến này.
Bạn có thể sử dụng _Bool, nhưng giá trị trả về phải là số nguyên (1 cho đúng, 0 cho sai). Tuy nhiên, nên bao gồm và sử dụng bool như trong C ++, như đã nói trong bài trả lời này từ diễn đàn daniweb , cũng như câu trả lời này , từ câu hỏi stackoverflow khác này:
_Bool: Kiểu boolean của C99. Chỉ nên sử dụng _Bool trực tiếp nếu bạn đang duy trì mã kế thừa đã xác định macro cho bool, true hoặc false. Mặt khác, các macro đó được tiêu chuẩn hóa trong tiêu đề. Bao gồm tiêu đề đó và bạn có thể sử dụng bool giống như trong C ++.
Các biểu thức điều kiện được coi là đúng nếu chúng khác không, nhưng tiêu chuẩn C yêu cầu các toán tử logic tự trả về 0 hoặc 1.
@Tom: #define TRUE! FALSE là xấu và hoàn toàn vô nghĩa. Nếu tệp tiêu đề đi vào mã C ++ được biên dịch, thì nó có thể dẫn đến các vấn đề:
void foo(bool flag);
...
int flag = TRUE;
foo(flag);
Một số trình biên dịch sẽ tạo cảnh báo về chuyển đổi int => bool. Đôi khi mọi người tránh điều này bằng cách làm:
foo(flag == TRUE);
để buộc biểu thức là một bool C ++. Nhưng nếu bạn #define TRUE! FALSE, bạn sẽ kết thúc với:
foo(flag == !0);
kết thúc bằng cách so sánh int-to-bool có thể kích hoạt cảnh báo bằng mọi cách.
Nếu bạn đang sử dụng C99 thì bạn có thể sử dụng _Bool
loại. Không #include
cần thiết. Bạn không cần phải đối xử với nó như một số nguyên, tuy nhiên, ở đâu 1
là true
và 0
là false
.
Sau đó bạn có thể định nghĩa TRUE
và FALSE
.
_Bool this_is_a_Boolean_var = 1;
//or using it with true and false
#define TRUE 1
#define FALSE 0
_Bool var = TRUE;
#include <stdbool.h>
sử dụng bool
, true
và false
như tiêu chuẩn muốn bạn.
Đây là những gì tôi sử dụng:
enum {false, true};
typedef _Bool bool;
_Bool
là một kiểu dựng sẵn trong C. Nó dành cho các giá trị boolean.
Bạn chỉ có thể sử dụng lệnh #define
như sau:
#define TRUE 1
#define FALSE 0
#define NOT(arg) (arg == TRUE)? FALSE : TRUE
typedef int bool;
Và sử dụng như sau:
bool isVisible = FALSE;
bool isWorking = TRUE;
isVisible = NOT(isVisible);
và như thế
arg
và toàn bộ biểu thức : #define NOT(arg) (((arg) == TRUE) ? FALSE : TRUE)
. Tuy nhiên, sẽ tốt hơn nếu kiểm tra độ giả (nó sẽ cho câu trả lời đúng ngay cả khi arg
là 23 thay vì 0 hoặc 1. #define NOT(arg) (((arg) == FALSE) ? TRUE : FALSE)
Nhưng tất nhiên, toàn bộ biểu thức có thể được giảm xuống #define NOT(arg) (!(arg))
, tất nhiên, tạo ra kết quả tương tự.