Tiêu chuẩn C có biểu thị rõ ràng giá trị chân lý là 0 hay 1 không?


86

Chúng ta biết rằng bất kỳ số nào không bằng 0được xem như truetrong C, vì vậy chúng ta có thể viết:

int a = 16;

while (a--)
    printf("%d\n", a);  // prints numbers from 15 to 0

Tuy nhiên, tôi đã tự hỏi liệu true / false có được định nghĩa là 1/ 0trong C hay không, vì vậy tôi đã thử mã bên dưới:

printf("True = %d, False = %d\n", (0 == 0), (0 != 0));  // prints: True = 1, False = 0

Tiêu chuẩn C có chỉ ra một cách rõ ràng các giá trị chân lý của true và false là 10tương ứng không?


3
Tôi đoán Câu hỏi SO này có liên quan
Imran Ali

3
Tôi cố gắng chạy điều này gccvới -std=c89và nó mang lại kết quả tương tự.
Kevin Dong,

1
@ Lỗ đen, từ 15 thành 0
Arturo Torres Sánchez

6
Gần như dupe nhưng hơn một thập kỷ trước SO / SE: c-faq.com/bool/bool2.html .
dave_thompson_085

1
Sai là 0 là canon, tuy nhiên true thường được coi là "không phải 0". Tuy nhiên, các lập trình viên là những gì họ đang có, tất cả chúng ta đã sử dụng 1 là "không phải là 0" vì nhiều lý do khác nhau của chúng ta. Bạn không nên tin tưởng giá trị true là chính xác 1. Trong khi (0 == 0) là một trong ví dụ của bạn, thì một cái gì đó như (12 == 12) có thể dễ dàng có giá trị 12; cũng "đúng".
Kỹ sư

Câu trả lời:


96

Tiêu chuẩn C có chỉ ra rõ ràng các giá trị chân lý của truefalsenhư 01tương ứng không?

Tiêu chuẩn C định nghĩa truefalsedưới dạng macro trong stdbool.hđó mở rộng đến 10tương ứng.

C11-§7.18:

Ba macro còn lại thích hợp để sử dụng trong các #ifchỉ thị tiền xử lý. họ đang

true

mở rộng thành hằng số nguyên 1,

false

mở rộng thành hằng số nguyên 0[...]

Đối với các nhà khai thác ==!=, tiêu chuẩn cho biết

C11-§6.5.9 / 3:

Các toán tử ==(bằng) và !=(không bằng) tương tự với các toán tử quan hệ ngoại trừ mức độ ưu tiên thấp hơn của chúng. 108) Mỗi toán tử cho kết quả 1nếu quan hệ được chỉ định là đúng và 0nếu nó là sai. Kết quả có loại int. Đối với bất kỳ cặp toán hạng nào, chính xác một trong các quan hệ là đúng.


20
Đối với tôi, dường như câu hỏi là về 0 == 00 != 0v.v., không phải giá trị của macro.
MM

9
Tôi nghĩ rằng khi anh ấy viết true, anh ấy có nghĩa là "giá trị của một so sánh thực sự" hoặc một cái gì đó, không phải vĩ môtrue
MM

1
@KevinDong; Có, dự thảo C99 có đoạn tương tự.
haccks

1
@haccks: bạn có thể nói về nó mà không ngần ngại "giống hệt" Tôi chỉ đưa câu trích dẫn của bạn lên vì tôi quá lười để tra cứu từng đoạn vì tôi đề cập đến c99 khi cần thiết. Và tôi có thể tìm thấy nó bằng cách chỉ tìm kiếm nó qua ctrl+ f;)
dhein

2
@MooingDuck: NaN == NaNsai và NaN != NaNđúng. Không có vấn đề gì với câu nói đó.
kennytm

51

Nó không được chỉ ra rõ ràng trong C11. Tất cả các thao tác cấp ngôn ngữ sẽ trả về 1 là true (và chấp nhận mọi ký tự khác bao gồm NaN là true).

  • Nếu bạn quan tâm _Bool, thì true phải là 1 vì tiêu chuẩn chỉ yêu cầu nó giữ 0 và 1. (§6.2.5 / 2).
  • Cũng trong <stdbool.h>macro truemở rộng thành 1(§7.18 / 3)
  • ==, !=, <, >, <=>=trở về 0 hoặc 1 (§6.5.8 / 6, §6.5.9 / 3).
  • !, &&||trở về 0 hoặc 1 (§6.5.3.3 / 5, §6.5.13 / 3, §6.5.14 / 3)
  • defined mở rộng thành 0 hoặc 1 (§6.10.1 / 1)

Nhưng tất cả các hàm thư viện tiêu chuẩn, ví dụ islowerchỉ cần nói "nonzero" là đúng (ví dụ: §7.4.1 / 1, §7.17.5.1 / 3, §7.30.2.1 / 1, §7.30.2.2.1 / 4).


§6.2.5 / 2 : Một đối tượng được khai báo là kiểu _Boolđủ lớn để lưu trữ các giá trị 0 và 1.

§6.5.5.3 / 5 : Kết quả của toán tử phủ định logic !là 0 nếu giá trị của toán hạng của nó so sánh không bằng 0, 1 nếu giá trị của toán hạng của nó so sánh bằng 0.…

§6.5.8 / 6 : Mỗi toán tử <(nhỏ hơn), >(lớn hơn), <=(nhỏ hơn hoặc bằng), và >=(lớn hơn hoặc bằng) sẽ mang lại kết quả 1 nếu quan hệ được chỉ định là đúng và 0 nếu nó là sai. 107)…

§6.5.9 / 3 : Các toán tử ==(bằng) và !=(không bằng) tương tự với các toán tử quan hệ ngoại trừ mức độ ưu tiên thấp hơn của chúng.108) Mỗi ​​toán tử cho kết quả là 1 nếu quan hệ được chỉ định là đúng và 0 nếu là sai. …

§6.5.13 / 3 : &&Toán tử sẽ mang lại kết quả 1 nếu cả hai toán hạng của nó so sánh không bằng 0; …

§6.5.14 / 3 : ||Toán tử sẽ mang lại kết quả 1 nếu một trong các toán hạng của nó so sánh không bằng 0; …

§6.10.1 / 1 :… nó có thể chứa các biểu thức toán tử một bậc có dạng - defined identifier- hoặc - defined ( identifier )- đánh giá là 1 nếu…

§7.4.1 (Các hàm phân loại ký tự) / 1 : Các hàm trong mệnh đề con này trả về khác không (true) nếu và chỉ khi…

§7.18 / 3 : Ba macro còn lại thích hợp để sử dụng trong các #ifchỉ thị tiền xử lý. Chúng là - true- mở rộng thành hằng số nguyên 1,…

§7.17.5.1 / 3 : Hàm atomic_is_lock_freechung trả về khác không (true) nếu và chỉ khi các hoạt động của đối tượng là không có khóa. …

§7.30.2.1 (Các hàm phân loại ký tự rộng) / 1 : Các hàm trong mệnh đề con này trả về khác không (true) nếu và chỉ khi…

§7.30.2.2.1 / 4 : iswctypeHàm trả về nonzero (true) nếu và chỉ khi…


23

Có hai lĩnh vực của tiêu chuẩn mà bạn cần lưu ý khi xử lý các giá trị Boolean (theo ý tôi là giá trị true / false chứ không phải là bool/_Boolloại C cụ thể ) trong C.

Đầu tiên phải làm với kết quả của các biểu thức và có thể được tìm thấy trong các phần khác nhau của C11 6.5 Expressions(ví dụ: các toán tử quan hệ và bình đẳng). Điểm mấu chốt là, bất cứ khi nào giá trị Boolean được tạo bởi một biểu thức, nó ...

... cho kết quả 1 nếu quan hệ được chỉ định là đúng và 0 nếu quan hệ đó là sai. Kết quả có kiểu int.

Vì vậy, có, kết quả của bất kỳ biểu thức tạo Boolean nào sẽ là một cho true hoặc bằng 0 cho false. Điều này khớp với những gì bạn sẽ tìm thấy ở stdbool.hnơi các macro tiêu chuẩn truefalseđược xác định theo cùng một cách.

Tuy nhiên, hãy nhớ rằng, tuân theo nguyên tắc vững chắc là "thận trọng với những gì bạn gửi, tự do trong những gì bạn chấp nhận", việc giải thích các số nguyên trong ngữ cảnh Boolean có phần thoải mái hơn.

Một lần nữa, từ các phần khác nhau của 6.5, bạn sẽ thấy ngôn ngữ như:

Các ||nhà điều hành sẽ mang lại 1 nếu một trong hai toán hạng của nó so sánh không công bằng 0; ngược lại, nó cho ra 0. Kết quả có kiểu int.

Từ đó (và các phần khác), rõ ràng là số 0 được coi là sai và bất kỳ giá trị nào khác là đúng.


Ngoài ra, ngôn ngữ chỉ định giá trị nào được sử dụng cho quá trình tạo và diễn giải Boolean cũng xuất hiện trở lại trong C99 và C89, vì vậy chúng đã xuất hiện khá lâu. Ngay cả K&R (ANSI-C phiên bản thứ hai phiên bản đầu tiên) đã chỉ định rằng, với các phân đoạn văn bản như:

Biểu thức quan hệ như i > jvà biểu thức logic được kết nối bởi &&||được định nghĩa để có giá trị 1nếu đúng và 0nếu sai.

Trong phần thử nghiệm của if, while, for, vv, "true" chỉ có nghĩa là "non-zero".

Các &&nhà điều hành ... trả về 1 nếu cả hai toán hạng của nó so sánh không đồng đều bằng không, 0 nếu ngược lại.

Các ||nhà điều hành ... trả về 1 nếu một trong hai toán hạng của nó so sánh không đồng đều bằng không, và 0 nếu ngược lại.

Các macro trong cũng stdbool.hxuất hiện trong C99, nhưng không xuất hiện trong C89 hoặc K&R vì tệp tiêu đề đó không tồn tại vào thời điểm đó.


2
lưu ý rằng ||, ==, !=, vv năng suất int, không phải là một kiểu boolean
MM

2
Tôi bình chọn câu hỏi này cho câu hỏi đúng. Đối với tôi, câu hỏi cũng là về các toán tử quan hệ chứ không phải macro.
ckruczek

"Trong phần thử nghiệm của if, while, for, vv, "true" chỉ có nghĩa là "non-zero"." Đây là phần nổi bật của câu trả lời và theo tôi, đó là một lựa chọn đáng tiếc của Dennis Ritchie từ lâu. Bất kỳ ai đã viết các hàm trả về mã lỗi như giá trị trả về thường có #define noErr 0và bất kỳ mã lỗi nào khác 0 đều là lỗi. Và sau đó vấn đề là sự đơn giản và đẹp đẽ của if ( ready_to_do_something() ){do_something();} không hoạt động. Nó phải là if ( !not_ready_to_do_something() ){do_something();}"Có rất nhiều điều giả dối, nhưng chỉ có một sự thật." TRUE phải là 0.
robert bristow-johnson

Không khỏi tò mò, bản nháp đầu tiên của quy tắc C đã chỉ rõ hành vi của "&&" và "||" như thế nào trong trường hợp toán hạng có giá trị khác 0 hoặc 1? Văn bản bạn trích dẫn cho biết "biểu thức logic" được kết nối bởi && và ||, nhưng nếu những toán tử đó kết nối những thứ khác với biểu thức logic thì sao?
supercat

1
@sdenham, vâng. Trong bản sao sớm nhất của K&R mà tôi có (ấn bản đầu tiên, bản in 14, một bản sớm đến mức đề cập đến các đặc điểm phần cứng của bốn máy điển hình, PDP-11, Honeywell-6000, IBM-370 và Interdata-8/32), A.7.6/7/10/11(quan hệ / bình đẳng / logic-và / logic-hoặc) đều chỉ định rằng nó cho kết quả là 0 hoặc 1. Có câu trả lời cập nhật để bao gồm điều đó.
paxdiablo

10

Bạn đang trộn lẫn rất nhiều thứ khác nhau: câu lệnh điều khiển, toán tử và kiểu boolean. Mỗi người có quy tắc riêng của họ.

Câu lệnh điều khiển hoạt động giống như câu lệnh ví dụ if, C11 6.4.8.1:

Trong cả hai dạng, câu lệnh con đầu tiên được thực thi nếu biểu thức so sánh không bằng 0.

while, forvv có cùng một quy tắc. Điều này không liên quan gì đến "true" hoặc "false".

Đối với các toán tử được cho là mang lại kết quả boolean, chúng thực sự đang mang lại intgiá trị 1 hoặc 0. Ví dụ: các toán tử bình đẳng, C11 6.5.9:

Mỗi toán tử cho kết quả 1 nếu quan hệ đã chỉ định là đúng và 0 nếu sai

Tất cả những điều trên là do C không có kiểu boolean cho đến năm 1999, và ngay cả khi có kiểu boolean, các quy tắc trên vẫn không thay đổi. Vì vậy, không giống như hầu hết các ngôn ngữ lập trình khác, nơi các câu lệnh và toán tử mang lại kiểu boolean (như C ++ và Java), chúng chỉ mang lại một int, với giá trị bằng không hoặc không bằng không. Ví dụ, sizeof(1==1)sẽ cho 4 trong C nhưng 1 trong C ++.

Kiểu boolean thực tế trong C được đặt tên _Boolvà yêu cầu trình biên dịch hiện đại. Tiêu đề stdbool.hxác định các macro bool, truefalsemở rộng tới _Bool, 10tương ứng (để tương thích với C ++).


Tuy nhiên, nó được coi là phương pháp lập trình tốt để xử lý các câu lệnh điều khiển và toán tử như thể chúng thực sự yêu cầu / mang lại một kiểu boolean. Một số tiêu chuẩn mã hóa như MISRA-C khuyến nghị thực hành như vậy. Đó là:

if(ptr == NULL)thay vì if(ptr).

if((data & mask) != 0)thay vì if(data & mask).

Mục đích của phong cách như vậy là để tăng độ an toàn của kiểu với sự hỗ trợ của các công cụ phân tích tĩnh, do đó làm giảm lỗi. Có thể cho rằng, kiểu này chỉ có ý nghĩa nếu bạn sử dụng máy phân tích tĩnh. Mặc dù trong một số trường hợp, nó dẫn đến mã tự ghi lại dễ đọc hơn, chẳng hạn

if(c == '\0') 

Tốt, mục đích rõ ràng, mã tự ghi lại.

đấu với

if(c) 

Xấu. Có thể có nghĩa là bất cứ điều gì, và chúng tôi phải đi tìm loại cđể hiểu mã. Nó là một số nguyên, một con trỏ hay một ký tự?


1
sizeof(bool)là triển khai cụ thể trong C ++. Xem stackoverflow.com/questions/4897844/is-sizeofbool-defined .
David Hammen

@DavidHammen Cũng như sizeof (0 == 0) cũng được xác định thực thi. Nó chỉ là một ví dụ.
Lundin

Tôi nghĩ C đã thay đổi các quy tắc cho các kiểu Boolean. Các kiểu uintN khác (bao gồm nhiều kiểu "bit" của trình biên dịch cũ hơn) lưu trữ N bit thấp hơn của một giá trị và bỏ qua bất kỳ bit nào cao hơn, trong khi kiểu Boolean mới có hiệu quả "hoặc" gộp tất cả các bit.
supercat

1
Điều đó nên if(ptr != NULL), hoặc có lẽ if(!ptr)?
Mathieu K.

1
if(c == '\0')Chính nó đã mắc phải lỗi viết mã đặc biệt phổ biến cho người mới bắt đầu if(c = '\0'), vì vậy tôi tránh nó. Đồng ý, if(c)là xấu ... nó phải là, ví dụ,if(valveIsOpen)
aja

4

Tôi đã lập trình bằng nhiều ngôn ngữ. Tôi đã thấy true là 1 hoặc -1 tùy thuộc vào ngôn ngữ. Logic đằng sau true là 1 là một bit hoặc là 0 hoặc 1. Logic đằng sau true là -1 là! toán tử là một bổ sung của một người. Nó đã thay đổi tất cả số 1 thành số 0 và tất cả số 0 thành số 1 trong một số nguyên. Vì vậy, đối với một int,! 0 = -1 và! (- 1) = 0. Điều này đã khiến tôi gặp khó khăn đến mức tôi không so sánh một cái gì đó là == true, mà thay vào đó so sánh nó là! = False. Bằng cách đó, phong cách lập trình của tôi hoạt động trên mọi ngôn ngữ. Vì vậy, câu trả lời của tôi là đừng lo lắng về điều đó, nhưng hãy lập trình để mã của bạn hoạt động chính xác theo cả hai cách.


Có thể như thế nào ! thay đổi tất cả các số 0 thành 1 và vẫn tạo ra 0 cho! 5?
Codehot

@codeshot Nó không thể. Nhưng quan điểm của anh ấy là không phải tất cả các ngôn ngữ đều xử lý toán hạng của! dưới dạng boolean. Một số điều trị! as C's ~ - nghĩa là một phần bổ sung bitwise. Trong trường hợp đó, việc xác định giá trị kết quả đòi hỏi phải biết kiểu của biến ngay từ đầu, vì vậy! (Uint32_t) 5 sẽ là 4,294,967,290. Nhưng 0 vẫn là 4,294,967,295 và 4,294,967,295 là sự thật.
Pegasus Epsilon

1

Câu trả lời này cần được xem xét kỹ hơn một chút.

Định nghĩa thực tế trong C ++ là bất kỳ thứ gì không phải 0 đều được coi là đúng. Tại sao điều này có liên quan? Bởi vì C ++ không biết số nguyên là gì bằng cách chúng ta nghĩ về nó - chúng ta tạo ra ý nghĩa đó, tất cả những gì nó nắm giữ là vỏ và quy tắc cho ý nghĩa của nó. Nó biết bit là gì, tạo nên một số nguyên.

1 như một số nguyên được biểu diễn lỏng lẻo theo bit, giả sử int 8 bit có dấu là 0000 0001. Nhiều khi những gì chúng ta nhìn thấy bằng mắt thường là một chút dối trá, -1 là cách phổ biến hơn nhiều để biểu diễn nó vì bản chất có dấu của 'số nguyên'. 1 thực sự không thể có nghĩa là đúng sự thật, tại sao? Bởi vì nó KHÔNG hoạt động là 1111 1110. Đó là một vấn đề thực sự lớn đối với boolean. Khi chúng ta nói về boolean, nó chỉ là 1 bit - nó thực sự đơn giản, 0 là sai và 1 là đúng. Tất cả các hoạt động logic diễn ra như tầm thường. Đây là lý do tại sao '-1' nên được chỉ định là 'đúng' cho các số nguyên (có dấu). 1111 1111 NOT'ed trở thành 0000 0000 --- logic đúng và chúng ta ổn. Các int không dấu là một chút phức tạp và được sử dụng phổ biến hơn trong quá khứ - trong đó 1 có nghĩa là true bởi vì nó dễ ám chỉ logic rằng '

Đó là lời giải thích. Tôi nói câu trả lời được chấp nhận ở đây là sai - không có định nghĩa rõ ràng trong định nghĩa C / C ++. Một boolean là một boolean, bạn có thể coi một số nguyên như một boolean, nhưng thực tế đầu ra là một số nguyên không nói lên điều gì về hoạt động thực sự đang được thực hiện là bitwise.


4
Câu hỏi là về C, không phải C ++.
glglgl

0

Nó xảy ra do các Toán tử quan hệ trong printftuyên bố của bạn .

Người điều hành ==và vận hành!=

(0 == 0)đúng như vậy, nó mang lại một giá trị1

trong khi, (0 != 0)không đúng như vậy, cho một giá trị 0.

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.