Cでのブール値の使用


回答:


1049

最高から最低まで:

オプション1(C99)

#include <stdbool.h>

オプション2

typedef enum { false, true } bool;

オプション3

typedef int bool;
enum { false, true };

オプション4

typedef int bool;
#define true 1
#define false 0

説明

  • オプション1は、C99を使用する場合にのみ機能し、それが「標準的な方法」です。可能であればこれを選択してください。
  • オプション2、3、および4は、実際には同じ同じ動作をします。#2と#3は#definesを使用しません。

まだ決まっていない場合は、#1に進んでください。


1
それらが最悪の選択に最適な理由を詳しく説明できますか?
Janlith

1
@endolith <stdbool.h> boolコンパイラーが選択する配置、最適化、およびコンパイラーの保管方法は、ブール値の使用目的よりもint(コンパイラーがとはbool異なる実装を選択する可能性があるためint)ブール値の使用目的に適している場合があります。運が良ければ、コンパイル時に型チェックが厳密になる可能性もあります。
blubberdiblub

1
なぜ使用intするのboolですか?それは無駄です。を使用しunsigned charます。または、Cの組み込みを使用します_Bool
user12211554

@NoBody小さい型を使用すると、メモリを節約できますが、高速になることはありません。多くの場合、それはそれを正しく整列するために、それはコンパイラを必要とする可能性があるとして、ビットシフトを作るために小さいサイズのではなく、プロセッサのネイティブワードサイズを使用するために高速です
テッド・クラインバーグマン

241

Cのブール値に関するいくつかの考え:

私は十分に古くint、typedefやtrue / false値の特別な定義や列挙をせずに、プレーンsをブール型として使用するだけです。ブール定数に対して決して比較しないという以下の私の提案に従うなら、とにかくフラグを初期化するために0/1を使用する必要があるだけです。しかし、このようなアプローチは、これらの現代ではあまりにも反動的であると見なされる場合があります。その場合、<stdbool.h>少なくとも標準化されているという利点があるので、間違いなく使用する必要があります。

ブール定数の名前が何であれ、初期化のみに使用します。次のようなことは決して書いてはいけません

if (ready == TRUE) ...
while (empty == FALSE) ...

これらは常により明確なものに置き換えることができます

if (ready) ...
while (!empty) ...

これらは実際には合理的かつ理解可能に大声で読み上げることができることに注意してください。

ブール変数に正の名前を付けます(例:のfull代わりに)notfull。後者は、簡単に読み取るのが難しいコードにつながります。比較する

if (full) ...
if (!full) ...

if (!notfull) ...
if (notfull) ...

前者のペアはどちらも自然!notfullに読み取られますが、そのままでも読みにくく、より複雑なブール式ではさらに悪くなります。

ブール値の引数は、通常は避ける必要があります。このように定義された関数を考えます

void foo(bool option) { ... }

関数の本体内では、便利でうまくいけば意味のある名前が付いているため、引数の意味は非常に明確です。しかし、呼び出しサイトは次のようになります

foo(TRUE);
foo(FALSE):

ここでは、関数の定義や宣言を常に見ていないと、パラメーターの意味を理解することは基本的に不可能であり、さらにブール型パラメーターを追加するとすぐに、事態はさらに悪化します。私はどちらかを提案します

typedef enum { OPT_ON, OPT_OFF } foo_option;
void foo(foo_option option);

または

#define OPT_ON true
#define OPT_OFF false
void foo(bool option) { ... }

どちらの場合も、呼び出しサイトは次のようになります。

foo(OPT_ON);
foo(OPT_OFF);

読者は、少なくともの定義に手を加えることなく理解できる可能性がありfooます。


1
また、2つの変数が等しいかどうかをどのように比較しますか?ブール定数を使用することはできませんが、非定数と比較した場合の問題は解決されません。
Baruch

私を許してください、しかし私は質問を理解しません。2つのブール変数が等しいかどうかを比較する方法を尋ねていますか?もしそうなら、動作しませんa == bか?
デールハグルンド2014

5
@ケンジあなたが言うことは本当ですが、1以外の値をtrueと同等として使用することはほとんど常に悪い考えだと思います。だからあなたの例では、と仮定 aしてb、ゼロからカウントアップ、私はお勧めしますa > 0 == b > 0代わりに。ゼロ以外の任意の値の真実性を利用すると主張!!varするとvar、と同等のブール値0/1が生成されるため、を書くことができますが!!a == !!b、多くの読者は混乱を招きます。
Dale Hagglund、2015年

3
!a == !b同等性のテストにも十分であり、非ゼロはゼロになり、ゼロは1になります。
ryanpattison 2015

5
@rpattisoもちろんそのとおりですが!!a、「ブール値ではないaを同等の真理値に変換する」と読んだ方が!a、「ブール値の変数aを論理的に反転させる」と読んだと思います。特に、論理反転が必要な特定の理由を探します。
デールハグルンド、2015


74

これが私が使ったバージョンです:

typedef enum { false = 0, true = !false } bool;

falseの値は1つだけですが、論理trueは多くの値を持つ可能性がありますが、テクニックはfalseの反対にコンパイラが使用するものをtrueに設定します。

これは誰かがこれに帰着する何かをコーディングする問題を処理します:

if (true == !false)

これは良い習慣ではないことは誰もが認めると思いますが、「true =!false」を実行するための一時的なコストで、その問題は解消されます。

[編集]最後に私が使用した:

typedef enum { myfalse = 0, mytrue = !myfalse } mybool;

定義していた他のスキームとの名前の衝突を回避しtruefalse。しかし、コンセプトは同じです。

[編集]整数からブールへの変換を表示するには:

mybool somebool;
int someint = 5;
somebool = !!someint;

最初(最も右)!ゼロ以外の整数を0に変換し、次に2番目(左端)に!0をmyfalse値に変換します。読者がゼロ整数を変換する練習として残しておきます。

[編集]デフォルト値が同じであっても特定の値が必要な場合は、列挙型の値の明示的な設定を使用するのが私のスタイルです。例:falseはゼロである必要があるため、使用するのfalse = 0,ではなくfalse,


5
また、列挙型を使用する別の利点は、IDEとの統合である- truefalseboolは対照的に、彼らは、列挙型の値とのtypedefであるため、ほとんどのIDEの中で強調表示され#defines、めったに構文が強調表示されています。

好奇心が強い:それが実際に機能するかどうかを無視して、列挙型同じ列挙型の前の値を参照できるようにするのは有効なC(99+)ですか?

@ tgm1024 gcc -ansi -pedantic -Wallは警告を出さないので、信頼しgccます。これがうまくc89いくなら、それもうまくいくはずc99です。
yyny

1
「falseの値は1つだけですが、論理trueは多くの値を持つ可能性がありますが、テクニックはtrueをコンパイラーがfalseの反対に使用するものに設定します。」否定演算子は、!値のみを返すことができます0し、1ので、true = !false常に割り当て値1は、この方法では、上の余分な安全性を与えるものではありませんでしょうtypedef enum { false, true } bool;
user694733

1
私が見つけた最も古いものはC90(6.3.3.3単項算術演算子)からのものです。「オペランドの値が0と等しくない場合、論理否定演算子!の結果は0です。オペランドの値が0と等しい場合、1です。結果の型はintです。式!Eは(O == E)と同等です。これは、標準Cをサポートすると主張しているすべてのコンパイラーをカバーするはずです。当然のことながら、コンパイラーは、監視可能な動作(のようなif(!value))が重要ではない場合、このルールを法的に無視できますが、この例外はこの特定のケースには適用されません。
user694733


30

まず最初に。C、つまりISO / IEC 9899は、19年間ブール型になりました。これは、この質問にアクセスしたときに、アマチュア/アカデミック/プロフェッショナルのパーツを組み合わせたCプログラミングキャリアの予想れる長さよりもはるかに長い時間です。鉱山はたぶんたった1-2年でそれを超えます。これは、平均的な読者がCについて何も学んでいない間、Cは実際にはブール型のデータ型を持っていたことを意味します。ます。

データ型については#include <stdbool.h>、使用truefalseおよびbool。それとも、および使用を含んでいない_Bool10代わりに。


このスレッドに対する他の回答では、さまざまな危険な行為が奨励されています。私はそれらに対処します:

typedef int bool;
#define true 1
#define false 0

19年以内にCを習得したカジュアルな読者boolは、実際の boolデータ型を参照して同じように動作することを期待しているはずですが、実際はそうではないためです。例えば

double a = ...;
bool b = a;

C99でbool/ _Boolbに設定されますfalse IFF aゼロだった、とtrueそうでありません。C11 6.3.1.2p1

  1. スカラー値がに変換される_Boolと、値が0と等しい場合、結果は0になります。それ以外の場合、結果は1になります。59)

脚注

59)NaNは0と比較しないため、1に変換されます。

typedef代わりに、doubleに強制変換されるだろうint-ダブルの値が用範囲内にない場合int動作は未定義です

当然、同じことはif truefalseで宣言され、enum

何でもあるより危険を宣言しています

typedef enum bool {
    false, true
} bool;

今ので、すべての値 1と0以外には無効であり、そのような値は、その型の変数に代入されるべきで、動作は完全に定義されていないことになります

したがって、場合に限っあなたには、いくつかの不可解な理由のためにC99を使用することはできません、ブール変数のためにあなたが使用する必要があります。

  • タイプintと値0、および現状の1 まま。そして、他の値からこれらの値へのドメイン変換を二重否定で慎重に行う!!
  • またはあなたがあれば主張あなたは0がfalsyであり、非ゼロtruish、少なくとも使用することを覚えていないアッパーケースを、彼らはC99の概念と混同されないように:BOOLTRUEFALSE

1
C規格のどの部分が、列挙型のオブジェクトを明示的にリストされた値を保持するように制限しますか?列挙定数の最大値がUCHAR_MAXまたはUSHRT_MAXより小さい場合、実装は列挙よりも小さい型intまたはunsigned int列挙型を保持するために使用できますが、列挙型が整数以外として動作する原因となる標準には何も知りませんタイプ。
スーパーキャット2018年

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

2
2〜MAX_INTもtrueに評価される必要があります
テクノサウルス

2
@technosaurusこのアプローチをとっても、!false == trueは保証されません。簡単な回避策は、trueを!falseに明示的に割り当てることです。
Andrew

3
@Andrewそうではありません。!0 = 1C標準、および!a = 0ゼロ以外の値の場合a。問題は、ゼロ以外の値が真と見なされることです。したがって、aとのb両方が「真」である場合、 `a == b`であるとは限りません。
ジェレミーウェスト

14

Cのブール型はbool(少なくとも過去10年間)です。

stdbool.hをインクルードすると、true / falseが期待どおりに機能します。


12
標準では10年ですが、コンパイラでは10年ではありません!MSVC ++のCコンパイルは、//コメントを許可する以外はC99をサポートしておらず、そうする可能性はほとんどありません。また、_BoolはC99で組み込み型として定義されていますが、boolは<stdbool.h>ヘッダーのtypedefです。
クリフォード、

5
@Cliffordコメントから4年後...何も変更されていません。MSVCはC ++コンパイラーであり、MSはすべての新しいC機能(C99およびC11)のサポートにそれほど熱心ではないと述べていると思います。しかし、理由としてMSVCが新しいC機能をサポートしていないことは理解できません(特に、10年の回答に対してそれを言った場合)。プログラミングの世界では、10年は本当に長い時間です。ベンダーがサポートするつもりであれば、まともなコンパイラーも10年も経たないうちにそれをサポートするはずです。
PP

2
@KingsIndian:なぜあなたが私にコメントを送ったのか、あるいはコメントする必要性を感じたのかはわかりません。私が書いている時点での状況を説明するだけでした。私はその状況をサポートしていませんでした。単に「答え」がすべての状況に当てはまるわけではないかもしれないと指摘しただけです。
クリフォード

@Clifford:厳密には、標準はboolに展開するマクロである必要があります_Bool#undefマクロは可能ですが(少なくとも移行措置としては許可されます)、untypedeftypedef はできないため、違いは重要です。ただし、最初のコメントの主な目的は変わりません。
ジョナサンレフラー、

2
VS2015以降では(&おそらくそれ以前の、最大のポイントまで)に問題がないboolを通じて<stdbool.h>Cのコンパイルの下で。それはに解決され_Boolます。

11

ブール演算ではゼロ以外のものはすべてtrueと評価されるので、

#define TRUE 1
#define FALSE 0

定数を使用します。


10
ただし、注意して使用してください。真の結果はゼロ以外の値になる可能性があるため、他の言語では同等のテストif(t == TRUE){...}とif(t)は、Cでは同等ではありません。 。
Fortega

1
あなたは正しいですが、ブール型を持っているC ++でもそうですよね?デバッグ中に、5837834939の値を持つブール変数を確認しました...
ggambett 09

1
C ++では、if(t == true)テストはif(t)テストと同じです。これは、C ++が何らかの変換を行うためです(0以外のすべてまたはnullポインター値がtrueに変換されます)
Fortega

6
ブールの真の値についてあなたが仮定する必要があるのは、それが非ゼロであることだけです。したがって、if(b == TRUE)は安全ではないが、if(b)のようなコードは安全です。後者は悪い習慣です(そして無意味です)。
クリフォード

5

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

私の好みのいくつか:

  • _Boolまたはbool?どちらも問題ありませんがbool、キーワードよりも見栄えがします_Bool
  • 以下のために受け入れ値boolとは_Bool、次のとおりですfalsetrue。割り当て0または1の代わりに、falseまたはtrue有効であるが、論理の流れを読み、理解することは困難です。

標準からのいくつかの情報:

  • _Boolはないがunsigned int符号なし整数型のグループの一部である。値を保持するのに十分な大きさ0または1です。
  • しないでください。ただし、再定義bool trueしてfalseしかし確かに良いアイデアではありません。この機能は廃止されたと見なされ、将来削除される予定です。
  • 割り当てスカラー型に(算術型およびポインタタイプ)_Bool、またはbool、場合スカラー値が同一である0か、と比較する0ことがあろう0、そうでなければ結果は1_Bool x = 9; 9に変換される1に割り当てられた場合x
  • _Boolは1バイト(8ビット)です。通常、プログラマは他のビットを使用しようとする傾向がありますが、推奨されるのは1ビットだけがデータを格納するために使用されるcharということです。利用可能なビット。


2

char、または別の小さなコンテナを使用できます。

疑似コード

#define TRUE  1
#define FALSE 0

char bValue = TRUE;

また、Cでそれは通常int型だし、それは用途が.. int型という他のコードによって、精度の警告の損失を引き起こす可能性があります
トーマスBonini

スペースを手動で最適化している場合を除き、ハードウェアの通常のワードサイズ(例:通常はint)を使用することをお勧めします。一部のアーキテクチャでは、これらの変数のチェックをアンパック/マスクする必要があるため、パフォーマンスが大幅に低下するためです。
Kingsley

2

_Boolを使用することもできますが、戻り値は整数でなければなりません(trueの場合は1、falseの場合は0)。言ったようしかし、C ++のようにブール値を含めると、使用することをお勧めします 。この回答からdaniwebフォーラムだけでなく、この答えこの他のstackoverflowの質問から、:

_Bool:C99のブール型。_Boolを直接使用することは、bool、true、またはfalseのマクロをすでに定義しているレガシーコードを維持している場合にのみお勧めします。それ以外の場合、これらのマクロはヘッダーで標準化されます。そのヘッダーを含めれば、C ++と同じようにboolを使用できます。


2

条件式は、それらがゼロ以外の場合に真であると見なされますが、C標準では、論理演算子自体が0または1を返す必要があります。

@トム:#define TRUE!FALSEは悪く、完全に無意味です。ヘッダーファイルがコンパイル済みC ++コードに組み込まれると、問題が発生する可能性があります。

void foo(bool flag);

...

int flag = TRUE;
foo(flag);

一部のコンパイラは、int => bool変換に関する警告を生成します。時々人々はこれをすることによってこれを避けます:

foo(flag == TRUE);

式を強制的にC ++ boolにします。ただし、#define TRUE!FALSEを定義すると、次のようになります。

foo(flag == !0);

これは、とにかく警告をトリガーできるint-bool比較を行うことになります。


1

C99を使用している場合は、_Boolタイプを使用できます。#includesは必要ありません。ただし、1is true0isは整数のように扱う必要がありますfalse

その後、TRUEおよびを定義できます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>と使用booltrueおよびfalse標準は、あなたがしたいよう。
SSアン

1

現在、C99はブール型をサポートしていますが、#include <stdbool.h>です。

例:

#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; 
} 

出力:

0
1

0

これは私が使用するものです:

enum {false, true};
typedef _Bool bool;

_Bool Cの組み込み型です。ブール値を対象としています。


-2

#define次のようにディレクティブを使用するだけです。

#define TRUE 1
#define FALSE 0
#define NOT(arg) (arg == TRUE)? FALSE : TRUE
typedef int bool;

次のように使用します。

bool isVisible = FALSE;
bool isWorking = TRUE;
isVisible = NOT(isVisible);

等々


5
NOTマクロは、括弧argと式全体を保護する必要があります#define NOT(arg) (((arg) == TRUE) ? FALSE : TRUE)。しかし、それは偽りのためのテストに良いだろう(それがあっても正しい答えを与えるarg23の代わりに、0または1であった。#define NOT(arg) (((arg) == FALSE) ? TRUE : FALSE)しかし、式全体はに減らすことができる。#define NOT(arg) (!(arg))同じ結果を生成する、もちろん、。
ジョナサン・レフラー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.