Sử dụng các giá trị boolean trong C


Câu trả lời:


1049

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

Giải trình

  • Tùy chọn 1 sẽ chỉ hoạt động nếu bạn sử dụng C99 và đó là "cách tiêu chuẩn" để thực hiện. Chọn cái này nếu có thể.
  • Tùy chọn 2, 3 và 4 sẽ có trong hành vi giống hệt nhau. # 2 và # 3 không sử dụng #defines mặc dù, theo tôi thì tốt hơn.

Nếu bạn chưa quyết định, hãy đi với # 1!


1
Bạn có thể giải thích lý do tại sao chúng là lựa chọn tốt nhất cho đến tồi tệ nhất?
endolith

1
@endolith Việc căn chỉnh, tối ưu hóa và cách lưu trữ <stdbool.h> booltrì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 boolkhá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.
blubberdiblub

1
Tại sao sử dụng intcho 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.
dùng12211554

@NoBody Sử dụng loại nhỏ hơn có thể tiết kiệm bộ nhớ, nhưng nó có thể không làm cho nó nhanh hơn. Thông thường, sẽ nhanh hơn khi sử dụng kích thước từ gốc của bộ xử lý thay vì kích thước nhỏ hơn vì nó có thể yêu cầu trình biên dịch thay đổi bit để căn chỉnh chính xác
Ted Klein Bergman

241

Một vài suy nghĩ về booleans trong C:

Tôi đã đủ tuổi để tôi chỉ sử dụng ints đơ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à fullthay 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 !notfullrấ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.


1
Và làm thế nào để bạn so sánh hai biến cho bình đẳng? Không bao giờ sử dụng hằng số boolean hoạt động tuyệt vời, nhưng nó không giải quyết được vấn đề khi so sánh với hằng số.
Baruch

Tha lỗi cho tôi, nhưng tôi không hiểu câu hỏi. Bạn đang hỏi làm thế nào tôi so sánh hai biến boolean cho đẳng thức? Nếu vậy, không a == blàm việc?
Dale Hagglund

5
@Kenji Những gì bạn nói là đúng, mặc dù tôi tin rằng việc sử dụng các giá trị khác với giá trị tương đương với sự thật hầu như luôn là một ý tưởng tồi. Vì vậy, trong ví dụ của bạn, giả sử điều đó abtính từ 0, tôi khuyên bạn nên a > 0 == b > 0thay 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 ý, !!varsẽ 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.
Dale Hagglund

3
!a == !bcũ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.
ryanpattison 10/07/2015

5
@rpattiso Tất nhiên bạn hoàn toàn đúng, nhưng tôi đoán tôi sẽ đọc !!alà "chuyển đổi không boolean a thành giá trị thật tương đương của nó", trong khi tôi đọc !alà "đả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.
Dale Hagglund


74

Đâ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 truefalse. 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 myfalsegiá 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,


5
Ngoài ra một lợi ích khác để sử dụng enums là sự tích hợp IDE - true, falseboolđượ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.

Tò mò: Bỏ qua việc nó có thực sự hoạt động hay không, nó có hợp lệ C (99+) để cho phép một enum tham chiếu một giá trị trước đó trong cùng một phép liệt kê không?

@ tgm1024 gcc -ansi -pedantic -Wallkhô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 c89nó sẽ làm việc cho c99aswell.
yyny

1
"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." Toán tử phủ định !chỉ có thể trả về các giá trị 01vì vậy true = !falsesẽ 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;.
dùng694733

1
Tôi tìm thấy sớm nhất là từ C90 (6.3.3.3 Toán tử số học đơn nguyên): "Kết quả của toán tử phủ định logic! 0 nếu giá trị của toán hạng của nó so sánh bằng 0. 1 nếu giá trị của toán hạng của nó so sánh bằng 0. kết quả có kiểu int. Biểu thức! E tương đương với (O == E). " Điều đó sẽ bao gồm bất kỳ trình biên dịch nào từng tuyên bố hỗ trợ chuẩn C. Trình biên dịch tất nhiên có thể bỏ qua quy tắc này một cách hợp pháp trong trường hợp không quan trọng đối với hành vi có thể quan sát được (như if(!value)), nhưng ngoại lệ đó không được áp dụng trong trường hợp cụ thể này.
dùng694733


30

Đ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, falsebool. Hoặc không bao gồm nó, và sử dụng _Bool, 10thay 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, bsẽ được đặt thành false iff a bằng 0 và truengược lại. C11 6.3.1.2p1

  1. 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 typedefvị trí, doublesẽ 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 truefalseđượ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:

  • intvà các giá trị 01 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!!
  • hoặc nếu bạn nhấn mạnh bạn không nhớ rằng 0 là falsy và khác không truish, ít nhất là sử dụng chữ in hoa để họ không bị nhầm lẫn với các khái niệm C99: BOOL, TRUEFALSE!

1
Phần nào của Tiêu chuẩn C sẽ giới hạn các đối tượng thuộc loại liệt kê để giữ các giá trị được liệt kê rõ ràng trong đó? Nếu giá trị lớn nhất cho hằng số liệt kê nhỏ hơn UCHAR_MAX hoặc USHRT_MAX, thì việc triển khai có thể sử dụng loại nhỏ hơn inthoặ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.
supercat

18
typedef enum {
    false = 0,
    true
} t_bool;

2
2 đến MAX_INT cũng nên đánh giá là đúng
technosaurus

2
@technosaurus Thực hiện phương pháp này không đảm bảo! false == true vì! false có thể là bất kỳ số nào khác không. Một cách giải quyết đơn giản sẽ là gán rõ ràng đúng cho! False.
Andrew

3
@Andrew Điều đó không đúng. !0 = 1theo tiêu chuẩn C và !a = 0vớ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 abcả hai đều "đúng", thì không nhất thiết phải là `a == b`.
Jeremy West

14

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.


12
10 năm trong tiêu chuẩn, nhưng không phải 10 năm trong trình biên dịch! Trình biên dịch C của MSVC ++ hoàn toàn không hỗ trợ C99 ngoài việc cho phép // nhận xét và không bao giờ có thể làm như vậy. Ngoài ra _Bool được định nghĩa trong C99 là loại tích hợp, trong khi bool là một typedef trong tiêu đề <stdbool.h>.
Clifford

5
@Clifford 4 năm kể từ khi bình luận của bạn ... không có gì thay đổi. MSVC là trình biên dịch C ++ và tôi tin rằng MS đã nói rằng họ không thực sự quan tâm đến việc hỗ trợ tất cả các tính năng C mới (C99 & C11). Nhưng tôi không thể coi MSVC không hỗ trợ các tính năng C mới như một lý do (đặc biệt là khi bạn nói điều đó với câu trả lời 10 năm ). 10 năm thực sự là một khoảng thời gian dài trong thế giới lập trình. Bất kỳ trình biên dịch tử tế nào cũng cần có hỗ trợ cho nó trong vòng chưa đầy 10 năm nếu nhà cung cấp dự định hỗ trợ nó.
PP

2
@KingsẤn Độ: Tôi không chắc tại sao bạn lại gửi bình luận của bạn cho tôi hoặc thậm chí cảm thấy cần phải bình luận gì cả. Tôi chỉ nói rõ tình hình khi nó đứng tại thời điểm viết bài. Tôi đã không ủng hộ tình huống đó, chỉ đơn thuần chỉ ra rằng "câu trả lời" có thể không áp dụng trong mọi trường hợp.
Clifford

@Clifford: Nghiêm túc, tiêu chuẩn yêu cầu boolphải là một macro mở rộng _Bool. Sự khác biệt quan trọng bởi vì bạn có thể #undefmộ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ể untypedeflà 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.
Jonathan Leffler

2
VS2015 trở lên (và có thể sớm hơn, đến một điểm) không có vấn đề gì với boolviệc <stdbool.h>biên dịch theo C. Nó giải quyết _Bool.

11

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ố.


10
nhưng hãy cẩn thận khi sử dụng: vì một kết quả thực sự có thể là bất kỳ giá trị khác không, các phép thử if (t == TRUE) {...} và if (t), tương đương trong các ngôn ngữ khác, không tương đương trong C .
Fortega

1
Bạn nói đúng, nhưng điều đó cũng đúng trong C ++, có kiểu bool, phải không? Trong quá trình gỡ lỗi, tôi đã thấy các biến bool có giá trị 5837834939 ...
ggambett

1
Trong C ++, kiểm tra if (t == true) bằng với kiểm tra if (t), vì C ++ thực hiện một số chuyển đổi (mọi thứ không phải là 0 hoặc giá trị con trỏ null được chuyển đổi thành true)
Fortega

6
Tất cả những gì bạn nên giả sử về một giá trị thực boolean là nó khác không. Vì vậy, mã như if (b) là an toàn trong khi if (b == TRUE) thì không; thứ hai là thực hành xấu (và vô nghĩa).
Clifford

5

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:

  • _Boolhay bool? Cả hai đều tốt, nhưng booltrông tốt hơn so với từ khóa _Bool.
  • Các giá trị được chấp nhận cho bool_Boollà: falsehoặc true. Chỉ định 0hoặc 1thay vì falsehoặc truehợ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:

  • _Boollà 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ị 0hoặc 1.
  • KHÔNG, nhưng có, bạn có thể xác định lại bool truefalsechắ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.
  • Gán một loại vô hướng ( loại số học và loại con trỏ) cho _Boolhoặc bool, nếu giá trị vô hướng bằng 0hoặc so sánh với 00, nếu không, kết quả là 1: _Bool x = 9; 9được chuyển đổi thành 1khi được gán cho x.
  • _Boollà 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 charcó 8 bit có sẵn.

2

Nó là đây:

#define TRUE 1
#define FALSE 0

7
Id đi với một cái gì đó như #define TRUE! FALSE
Tom

2

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;

Ngoài ra trong C, nó thường là một int và nó có thể gây mất cảnh báo chính xác bởi các mã khác sử dụng int ..
Thomas Bonini

Trừ khi bạn tối ưu hóa không gian bằng tay, tốt hơn hết là sử dụng kích thước từ thông thường của phần cứng (ví dụ: thường là 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.
Kingsley

2

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 ++.


2

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.


1

Nếu bạn đang sử dụng C99 thì bạn có thể sử dụng _Boolloại. Không #includecầ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 1true0false.

Sau đó bạn có thể định nghĩa TRUEFALSE.

_Bool this_is_a_Boolean_var = 1;


//or using it with true and false
#define TRUE 1
#define FALSE 0
_Bool var = TRUE;

Hoặc bạn có thể #include <stdbool.h>sử dụng bool, truefalsenhư tiêu chuẩn muốn bạn.
SS Anne

1

Ngày nay C99 hỗ trợ các loại boolean nhưng bạn cần phải #include <stdbool.h>.

Thí dụ:

#include <stdbool.h>

int main() 
{ 
    bool arr[2] = {true, false}; 

    printf("%d\n", arr[0] && arr[1]);
    printf("%d\n", arr[0] || arr[1]);

    return 0; 
} 

Đầu ra:

0
1

0

Đâ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.


-2

Bạn chỉ có thể sử dụng lệnh #definenhư 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ế


5
Macro KHÔNG nên được bảo vệ bằng dấu ngoặc đơn xung quanh argvà 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 arglà 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ự.
Jonathan Leffler
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.