C標準は真理値を0または1として明示的に示していますか?


86

等しくない数はCのように0表示されることがわかっているtrueので、次のように書くことができます。

int a = 16;

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

しかし、true / falseがCで1/として定義されているかどうか疑問に思っていた0ので、以下のコードを試しました。

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

DOES C標準は、明示的真理として真と偽の値を示している10、それぞれの?


3
私はこのSOの質問が関連していると思います
Imran Ali 2016

3
私はこの下を実行しようgcc-std=c89、それは同じ結果が得られます。
ケビン・ドン

1
15から0に@Blackhole、
アルトゥーロトーレス・サンチェス

6
ほぼ重複していますが、SO / SEの前に10年以上:c-faq.com/bool/bool2.html
dave_thompson_085 2016年

1
falseがゼロであるということは正統ですが、trueは一般に「ゼロではない」と考えられています。プログラマーは彼ら自身ですが、私たちはさまざまな理由で1を「ゼロではない」として使用しています。trueが正確に1であると信頼しないことをお勧めします。(0 == 0)は例の1つですが、(12 == 12)のようなものは同じように簡単に値12を持つことができます。また、「真」。
エンジニア

回答:


96

C標準は、明示的真理の値を示していますtrueし、falseなど01それぞれの?

C標準ではtrue、とをそれぞれに展開するfalseマクロとして定義しています。 stdbool.h10

C11-§7.18:

残りの3つのマクロは、#ifディレクティブの前処理での使用に適しています。彼らです

true

これは整数定数に展開されます1

false

これは整数定数に展開され0ます[...]

オペレーター==!=、標準は言う

C11-§6.5.9/ 3:

==(等しい)と!=(等しくない)演算子は、それらの低い優先順位を除く関係演算子に類似しています。108)各演算子は1、指定された関係が真である0か偽であるかを示します。結果のタイプはintです。オペランドの任意のペアについて、関係の1つだけが真です。


20
質問が約あるように私には思える0 == 0し、0 != 0マクロの値ではない、など。
MM

9
彼が書いたとき、彼はtrueマクロではなく「真の比較の価値」か何かを意味していたと思いますtrue
MM 2016年

1
@KevinDong; はい、C99ドラフトにも同様の段落があります。
haccks 2016年

1
@haccks:「同一」を躊躇せずにそれについて言うことができます。必要なときにc99を参照するので、段落で調べるのが面倒だったので、引用を引用しました。そして、ctrl+で検索するだけで見つけることができましたf;)
dhein 2016年

2
@MooingDuck:NaN == NaN偽でNaN != NaNあり、真です。その声明に問題はありません。
kennytm 2016年

51

C11では明示的に示されていません。すべての言語レベルの操作は、1をtrueとして返します(そして、NaNを含むすべての非ゼロをtrueとして受け入れます)。

  • について懸念がある場合_Bool、標準では0と1のみを保持する必要があるため、trueは1でなければなりません(§6.2.5/ 2)。
  • また<stdbool.h>、マクロでtrue1(§7.18/ 3)に展開されます
  • ==!=<><=および>=戻り0または1(§6.5.8/ 6、§6.5.9/ 3)。
  • !&&および||0または1を返します(§6.5.3.3/ 5、§6.5.13/ 3、§6.5.14/ 3)
  • defined 0または1に展開します(§6.10.1/ 1)

しかし、すべての標準ライブラリ関数は、たとえばislower、真実を表すために「ゼロ以外」とだけ言います(たとえば、§7.4.1/ 1、§7.17.5.1/ 3、§7.30.2.1/ 1、§7.30.2.2.1/ 4)。


§6.2.5/ 2:型として宣言されたオブジェクトは_Bool、値0と1を格納するのに十分な大きさです。

§6.5.5.3/ 5:論理否定演算子の結果は、!そのオペランドの値が0と等しくない場合は0、オペランドの値が0と等しい場合は1です。…

§6.5.8/ 6:演算子<(より小さい)、>(より大きい)、<=(以下)、および>=(以上)のそれぞれは、指定された関係が真の場合は1、それが真の場合は0を生成します。は誤りです。107)…

§6.5.9/ 3 :(==等しい)および!=(等しくない)演算子は、優先順位が低いことを除いて、関係演算子に類似しています。108)各演算子は、指定された関係が真の場合は1、真の場合は0になります。 false。…

§6.5.13/ 3&&両方のオペランドが0と等しくない場合、演算子は1を生成します。…

§6.5.14/ 3||いずれかのオペランドが0と等しくない場合、演算子は1を生成します。…

§6.10.1/ 1:…次の形式の単項演算子式が含まれる場合があります— defined identifier—または— defined ( identifier )—次の場合は1と評価されます…

§7.4.1(文字分類関数)/ 1:この節の関数は、…の場合に限り、ゼロ以外(true)を返します。

§7.18/ 3:残りの3つのマクロは、#ifディレクティブの前処理での使用に適しています。それらは— true—整数定数1に展開されます…

§7.17.5.1/ 3atomic_is_lock_freeオブジェクトの操作がロックフリーである場合に限り、汎用関数はゼロ以外(true)を返します。…

§7.30.2.1(ワイド文字分類関数)/ 1:この節の関数は、…の場合に限り、ゼロ以外(true)を返します。

§7.30.2.2.1/ 4iswctype関数は、…の場合に限り、ゼロ以外(true)を返します。


23

Cでブール値(特定のCbool/_Boolタイプではなくtrue / false値を意味します)を処理するときに注意する必要がある標準の2つの領域があります。

1つ目は式の結果C11 6.5 Expressions関係があり、のさまざまな部分(関係演算子や等式演算子など)にあります。肝心なのは、ブール値が式によって生成されるときはいつでも、それは...

...指定された関係がtrueの場合は1、falseの場合は0になります。結果の型はintです。

したがって、はい、ブール生成式の結果は、trueの場合は1、falseの場合は0になります。これはあなたが見つけるものと一致するstdbool.h場所の標準マクロtruefalse同じように定義されています。

ただし、「送信するものは保守的で、受け入れるものは寛大である」というロバストネス原則に従うと、ブールコンテキストでの整数の解釈はやや緩和されることに注意してください。

繰り返し6.5ますが、のさまざまな部分から、次のような言語が表示されます。

||そのオペランドのいずれかがあれば1を得なければならないオペレータ0に等しくない比較します。それ以外の場合は0になります。結果の型はintです。

それ(および他の部分)から、ゼロが偽と見なされ他の値が真であることが明らかです。


余談ですが、ブール値の生成と解釈に使用される値を指定する言語は、C99とC89にも表示されるため、かなり前から存在しています。K&R(ANSI-C第2版および第1版)でさえ、次のようなテキストセグメントでそれを指定しました。

以下のような関係式i > jと論理式はで接続&&し、||値を持つように定義されている1場合はtrue、および0falseの場合。

、、、などのテスト部分でifwhilefor「真」は単に「非ゼロ」を意味します。

&&オペレータ...リターン1の両方のオペランドがゼロに等しくない比較する場合、そうでなければ0。

||オペレータは、...そうでなければ、そのオペランドのいずれかがゼロに等しくない比較する場合は1、及び0を返します。

のマクロはstdbool.hC99にも表示されますが、そのヘッダーファイルがその時点で存在していなかったため、C89またはK&Rには表示されません。


2
なお||==!=などの利回りintではなく、boolean型
MM

2
私はこの質問を正しいものに投票します。私にとっての質問は、マクロではなく、関係演算子についてです。
ckruczek 2016年

「、、、などのテスト部分でifwhilefor「真」は単に「ゼロ以外」を意味します。」これは答えの重要な部分であり、私の意見では、ずっと前からのデニス・リッチーの不幸な選択です。戻り値としてエラーコードを返す関数を書いた人は誰でも一般的に持って#define noErr 0おり、ゼロ以外のエラーコードはエラーです。そして問題は、のシンプルさと美しさがif ( ready_to_do_something() ){do_something();} 機能しないことです。それはif ( !not_ready_to_do_something() ){do_something();}「多くの虚偽がありますが、ただ一つの真実」でなければなりません。TRUEは0である必要があります
。– robert bristow-johnson 2016

好奇心から、Cルールの最初のドラフトは「&&」と「||」の動作をどのように指定しましたか オペランドの値が0または1以外の場合は?引用するテキストには、&&と||で接続された「論理式」と書かれていますが、これらの演算子が論理式以外のものを接続するとどうなるでしょうか。
スーパーキャット2016年

1
@sdenham、はい。私が持っているK&Rの最初のコピー(初版、印刷実行14、1つは非常に早いので、4つの典型的なマシン、PDP-11、Honeywell-6000、IBM-370、およびInterdata-8 / 32のハードウェア特性に言及しています)、A.7.6/7/10/11(relational / equality / logical-および/ logical-or)はすべて、結果として0または1を与えることを指定します。それを含めるために回答を更新しました。
paxdiablo 2016年

10

制御ステートメント、演算子、ブール型など、さまざまなものを混同しています。それぞれに独自のルールがあります。

制御ステートメントは、たとえばifステートメントC11 6.4.8.1のように機能します。

どちらの形式でも、式が0と等しくない場合、最初のサブステートメントが実行されます。

whileforなども同じルールです。これは「真」または「偽」とは何の関係もありません。

ブール結果を生成すると思われる演算子については、実際にはint値1または0のを生成しています。たとえば、等式演算子C11 6.5.9:

各演算子は、指定された関係が真の場合は1、偽の場合は0になります。

上記のすべては、Cが1999年までブール型を持っていなかったためであり、ブール型を取得した場合でも、上記のルールは変更されていません。したがって、ステートメントと演算子がブール型(C ++やJavaなど)を生成する他のほとんどのプログラミング言語とは異なりint、値がゼロまたはゼロではない、を生成するだけです。たとえばsizeof(1==1)、Cでは4、C ++では1になります。

Cの実際のブール型には名前が付けられて_Boolおり、最新のコンパイラが必要です。ヘッダstdbool.h定義マクロbooltruefalseに展開し_Bool1及び0(C ++との互換性のため)でした。


ただし、制御ステートメントと演算子を実際にブール型を必要とする/生成するかのように扱うことは、優れたプログラミング手法と見なされます。MISRA-Cのような特定のコーディング標準では、このような方法を推奨しています。あれは:

if(ptr == NULL)の代わりにif(ptr)

if((data & mask) != 0)の代わりにif(data & mask)

このようなスタイルの目的は、静的分析ツールを使用して型の安全性を高め、バグを減らすことです。間違いなく、このスタイルは、静的アナライザーを使用する場合にのみ意味があります。場合によっては、たとえば、より読みやすい自己文書化コードにつながります。

if(c == '\0') 

良い、意図は明確で、コードは自己文書化されています。

if(c) 

悪い。何かを意味cする可能性があり、コードを理解するためにタイプを探す必要があります。整数ですか、ポインタですか、それとも文字ですか?


1
sizeof(bool)C ++に固有の実装です。stackoverflow.com/questions/4897844/is-sizeofbool-definedを参照してください。
デビッドハメン2016年

@DavidHammen sizeof(0 == 0)が実装で定義されているのと同じように。これは単なる例です。
Lundin 2016年

Cはブール型のルールを変更したと思いました。他の種類のuintN型(多くの古いコンパイラの「ビット」型を含む)は、値の下位Nビットを格納し、上位ビットを無視しますが、新しいブール型はすべてのビットを効果的に「または」まとめます。
スーパーキャット2016年

1
それはif(ptr != NULL)、またはおそらくif(!ptr)ですか?
Mathieu K.

1
if(c == '\0')コーディングの特に一般的な初心者の間違いに役立つif(c = '\0')ので、私はそれを避けます。同意しました、if(c)悪いです...たとえば、次のようになりますif(valveIsOpen)
aja 2016年

4

私は多くの言語でプログラミングしました。言語に応じて、trueが1または-1になるのを見てきました。真の1の背後にある論理は、ビットが0または1のいずれかであるということでした。真の-1の背後にある論理は、!演算子は1の補数でした。intですべての1を0に変更し、すべての0を1に変更しました。したがって、intの場合、!0 = -1および!(-1)= 0です。これにより、何かを== trueと比較せず、代わりに!= falseと比較するのに十分なトリップが発生しました。そうすれば、私のプログラミングスタイルはすべての言語で機能します。だから私の答えはそれについて心配することではなく、あなたのコードがどちらの方法でも正しく機能するようにプログラムすることです。


どのようにすることができます !すべての0を1に変更しても、!5に対して0を生成しますか?
コードショット

@codeshotそれはできません。しかし、彼が指摘しているのは、すべての言語が!のオペランドを扱うわけではないということです。ブール値として。いくつかの御馳走!Cの〜-つまり、ビット単位の補集合として。この場合、結果の値を決定するには、最初に変数の型を知る必要があるため、!(uint32_t)5は4,294,967,290になります。しかし、!0はまだ4,294,967,295であり、4,294,967,295は真実です。
ペガサスイプシロン

1

この答えはもう少し詳しく調べる必要があります。

C ++の実際の定義では、0以外のものはすべてtrueとして扱われます。なぜこれが関係するのですか?C ++は、整数がどのように考えられているかを知らないため、その意味を作成します。保持するのは、シェルとそれが意味するルールだけです。それは、整数を構成するビットが何であるかを知っています。

整数としての1は、ビットで大まかに表されます。たとえば、8ビットのsignedintは00000001です。視覚的に見えるのは少しうそですが、符号付きの性質があるため、-1がはるかに一般的な方法です。 '整数'の。1は本当に正しいという意味ではありません、なぜですか?動作しないので11111110です。これはブール値にとって本当に大きな問題です。ブール値について話すとき、それはたった1ビットです-それは本当に単純で、0は偽であり、1は真です。すべての論理演算は些細なことです。これが、整数(符号付き)に対して「-1」を「true」として指定する必要がある理由です。1111 1111NOT'edは00000000になります---ロジックは保持され、問題はありません。unsigned intsは少しトリッキーで、過去にはもっと一般的に使用されていました。ここで、1は、次のロジックを暗示するのが簡単なため、trueを意味します。

それが説明です。ここで受け入れられた答えは間違っていると言います。C/ C ++の定義には明確な定義がありません。ブール値はブール値であり、整数をブール値として扱うことができますが、出力が整数であるという事実は、実際に実行されている操作についてビット単位で何も示していません。


4
質問はC ++ではなくCについてでした。
glglgl 2016年

0

これは、printfステートメントの関係演算子が原因で発生しました。

オペレーター==とオペレーター!=

以来(0 == 0)true、そうを保持し、それが値を与えます1

一方、(0 != 0)は当てはまらないので、値を与えます0

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.