単純に1ではなく、Cブールマクロで#define TRUE(1 == 1)を使用する理由


160

Cで定義を見たことがある

#define TRUE (1==1)
#define FALSE (!TRUE)

これは必要ですか?TRUEを1と定義し、FALSEを0と定義することの利点は何ですか?


35
その他:#define TRUE (’/’/’/’); #define FALSE (’-’-’-’)coding-guidelines.com/cbook/cbook1_1.pdf page 871 から取得
osgx

2
いいえ、それは無知な^不思議な情報によるパラノイアです。Cでは、1と0はすべての状況で同じです。
Jens

@osgxどういう意味ですか?
mrgloom

回答:


155

このアプローチは、実際に使用されますboolean(にと決意タイプtruefalse、コンパイラがサポートしている場合)。(具体的には、C ++)

ただし、C ++が(__cplusplusマクロを介して)使用されているかどうかを確認し、実際にtrueandを使用することをお勧めしますfalse

Cコンパイラでは、これは0およびと同等1です。
(括弧を削除すると、操作の順序により、括弧が壊れることに注意してください)


7
これは不正解です。ブールはここでは使用されません。の結果は1==1ですint。(stackoverflow.com/questions/7687403/…を参照してください。)
Mat

4
@Mat:C ++でも、boolean型は?
SLaks 2013年

9
質問にはCというタグが付いていますが、実際にはC ++では関係演算子はtrueorを返しfalseます。
マット

5
@Mat:C ++でうまく機能するように、そのようなコードはCヘッダーで記述されていると
思い

20
@SLaks C ++でうまくプレイしたい場合は#define TRUE true#define FALSE falseいつでも__cplusplus定義されます。
Nikos C.

137

答えは移植性です。およびの数値は重要TRUEFALSEはありません。何重要なことはのような文ということであるif (1 < 2)と評価されたif (TRUE)とのような文if (1 > 2)に評価if (FALSE)

確かに、Cでは、に(1 < 2)評価され1、に(1 > 2)評価される0ため、他の人が言ったように、コンパイラに関する限り、実際的な違いはありません。しかし、コンパイラが定義させることにより、TRUEおよびFALSE独自のルールに従って、あなたはプログラマにその意味が明示的に作っている、とあなたはあなたのプログラム内の一貫性や他のライブラリを保証している(他のライブラリと仮定すると、あなたがしたい... Cの規格に準拠しています驚きます)。


一部の履歴
一部のBASICはFALSE0およびTRUEとして定義されてい-1ます。多くの現代言語と同様に、ゼロ以外の値はと解釈されましたが、真であるブール式をTRUE評価しました-1。彼らのNOT操作は、1を追加して符号を反転することによって実装されました。したがって、「NOT x」はになりました-(x+1)。この副作用として、のような値はに5評価されますがTRUE、にもNOT 5評価されます-6。これもTRUE!この種のバグを見つけることは楽しいことではありません。

ベストプラクティス
を考えると事実上のゼロがあると解釈されていることをルールFALSE任意の非ゼロ値は以下のように解釈されてはTRUE、あなたがすべきにブール-探して式を比較しませんTRUEFALSE。例:

if (thisValue == FALSE)  // Don't do this!
if (thatValue == TRUE)   // Or this!
if (otherValue != TRUE)  // Whatever you do, don't do this!

どうして?多くのプログラマーは、intsをsとして扱うショートカットを使用しているためboolです。それらは同じではありませんが、コンパイラは通常それを許可します。したがって、たとえば、次のように書くことは完全に合法です

if (strcmp(yourString, myString) == TRUE)  // Wrong!!!

それ合法に見え、コンパイラは喜んでそれを受け入れますが、おそらくあなたが望むことをしません。の戻り値strcmp()

      0の場合yourString == myString
    <0の場合yourString < myString
    > 0の場合yourString > myString

したがって、上の行はの場合にTRUEのみ戻りますyourString > myString

これを行う正しい方法は、

// Valid, but still treats int as bool.
if (strcmp(yourString, myString))

または

// Better: lingustically clear, compiler will optimize.
if (strcmp(yourString, myString) != 0)

同様に:

if (someBoolValue == FALSE)     // Redundant.
if (!someBoolValue)             // Better.
return (x > 0) ? TRUE : FALSE;  // You're fired.
return (x > 0);                 // Simpler, clearer, correct.
if (ptr == NULL)                // Perfect: compares pointers.
if (!ptr)                       // Sleazy, but short and valid.
if (ptr == FALSE)               // Whatisthisidonteven.

プロダクションコードでこれらの「悪い例」のいくつかを見つけることがよくあり、経験豊富なプログラマーの多くは彼らに誓います。しかし、考慮してください。「正しい」バージョンは、それほど効率的ではなく、移植可能であることが保証されており、最も厳密なリンターでさえ合格し、新しいプログラマーでも理解できます。

それだけの価値はありませんか?


6
(1==1)よりもポータブルではありません1。コンパイラー自体の規則は、C言語の規則です。これは、等価性と関係演算子のセマンティクスについて明確で明確です。コンパイラーがこれを間違っているのを見たことがありません。
キーストンプソン

1
実際にによって返される値はstrcmp0よりも小さい、等しい、または0より大きいことがわかっています。-1、0、または1であるとは限らず、実装の速度を上げるためにこれらの値を返さないプラットフォームが存在します。もしそうならstrcmp(a, b) == TRUE、次にa > bその逆含意が保持しない場合があります。
Maciej Piechotka 2013年

2
@KeithThompson-おそらく「移植性」は間違った用語でした。ただし、(1 == 1)はブール値であることに変わりはありません。1はそうではありません。
Adam Liss 2013年

2
@AdamLiss:Cでは(1==1)1どちらもint値が1の定数式であり、意味的には同じです。それを知らない読者向けのコードを書くことができると思いますが、それはどこで終わりますか?
キーストンプソン2013年

2
'not' 5は、実際には、ビットレベルで-6です。
woliveirajr 2013年

51

この(1 == 1)トリックはTRUE、Cに対して透過的な方法で定義するのに役立ちますが、C ++でのより良いタイピングを提供します。"Clean C"(CまたはC ++としてコンパイルされる)という方言で書いている場合、またはCまたはC ++プログラマーが使用できるAPIヘッダーファイルを書いている場合、同じコードをCまたはC ++として解釈できます。

C翻訳単位で1 == 1は、とまったく同じ意味1です。と1 == 0同じ意味0です。ただし、C ++変換ユニットで1 == 1は、型を持っていboolます。したがって、TRUEそのように定義されたマクロは、C ++によく統合されます。

それがより良い統合する方法の例としては、例えば機能があればということであるfooため過負荷があるintとのためにbool、その後、foo(TRUE)選択しますbool過負荷を。TRUEがとして定義されているだけの場合1、C ++ではうまく機能しません。オーバーロードfoo(TRUE)が必要にintなります。

もちろん、C99は、導入booltrueおよびfalseこれらはC99とし、Cとその仕事ヘッダファイルで使用することができます

しかしながら:

  • C99 を定義TRUEFALSE(0==0)それ(1==0)よりも前に、およびそれよりも前に行われるこのプラクティス
  • C99から離れてC90で作業する十分な理由がまだあります。

CとC ++が混在するプロジェクトで作業していて、C99が不要な場合truefalsebool代わりに小文字を定義します。

#ifndef __cplusplus
typedef int bool;
#define true (0==0)
#define false (!true)
#endif

0==0とはいえ、このトリックは、C ++との相互運用を意図したものではないコードでも一部のプログラマーによって使用されています(使用されていますか?)。これは何も購入せず、プログラマーがCでブール値がどのように機能するかについて誤解していることを示唆しています。


C ++の説明が明確でない場合のために、ここにテストプログラムを示します。

#include <cstdio>

void foo(bool x)
{
   std::puts("bool");  
}

void foo(int x)
{
   std::puts("int");  
}

int main()
{
   foo(1 == 1);
   foo(1);
   return 0;
}

出力:

bool
int

CとC ++の混合プログラミングに関連するC ++関数のオーバーロードについてのコメントからの質問について。これらは、型の違いを示しています。C ++としてコンパイルtrueするboolときに定数を使用したい正当な理由は、明確な診断のためです。最高の警告レベルでは、整数をboolパラメーターとして渡すと、C ++コンパイラーは変換について警告する可能性があります。Clean Cで記述する理由の1つは、コードの移植性が高い(C ++コンパイラだけでなくC ++コンパイラでも理解されるため)だけでなく、C ++コンパイラの診断的意見を活用できることです。


3
素晴らしく、過小評価されている答え。の2つの定義がTRUEC ++で異なることはまったく明らかではありません。
user4815162342 2013年

4
オーバーロードされた関数は、CとC ++の両方としてコンパイルされるコードにどのように関連していますか?
キーストンプソン

@KeithThompsonオーバーロードだけではなく、適切なタイピング一般の問題でもあります。オーバーロードは、実際のところ、最も実用的な例です。もちろん、オーバーロードなしのC ++コード、テンプレート、および「C互換性」のために削除されたすべての「複雑な」ものは、型についてはほとんど気にしませんが、特定の言語の概念的な型の制限を無効にする必要があるわけではありません。
Christian Rau

1
@ChristianRau:「タイプはあまり気にしない」とはどういう意味ですか?型はC言語の中心です。Cプログラムのすべての式、値、およびオブジェクトには、明確に定義された型があります。CとC ++で異なる定義をしたい場合(CとC ++の両方としてコンパイルするコードを実際に作成する必要があるまれなケース)、#ifdef __cplusplus意図をより明確に表現するために使用できます。
キーストンプソン2013年

@KeithThompsonはい私はタイプの重要性を知っています。オーバーロードやテンプレートなどのすべての型認識機能がなければ、との区別のようなものは実際にはあまり重要ではboolありintません。これらは互いに暗黙的に変換可能であるため(そしてCでは実際には「同じ」であり、引用符に注意してください)ただし、2つの間で実際に分解する必要がある状況は多くありません。「それほど多くない」はおそらく重すぎ、「テンプレートとオーバーロードを使用したコードと比較してはるかに少ない」のほうが多分良いでしょう。
Christian Rau 2013年

18
#define TRUE (1==1)
#define FALSE (!TRUE)

に相当

#define TRUE  1
#define FALSE 0

Cで

関係演算子の結果は0or 1です。1==1評価されることが保証されている1!(1==1)まで評価されることが保証されています0

最初のフォームを使用する理由はまったくありません。ただし、ほとんどすべてのコンパイラでは定数式が実行時ではなくコンパイル時に評価されるため、最初の形式は効率が悪くないことに注意してください。これは、次のルールに従って許可されています。

(C99、6.6p2)「定数式は、実行時ではなく変換中に評価できるため、定数が可能な任意の場所で使用できます。」

TRUEおよびFALSEマクロにリテラルを使用しない場合、PC-Lintはメッセージ(506、定数値のブール値)を発行します。

Cの場合、TRUEとして定義する必要があります1。ただし、他の言語は1以外の量を使用するため、一部のプログラマー!0は安全にプレイしていると感じています。

また、C99では、stdbool.hブールマクロの定義truefalse リテラルを直接使用します。

#define true   1
#define false  0

1
私は疑いがあります、TRUEはすべての使用で1 == 1に置き換えられますが、1を使用するだけで1が置き換えられますか?
pinkpanther 2013年

4
@pinkpanther定数式は通常コンパイル時に評価されるため、オーバーヘッドを引き起こしません。
ouah

2
1==1評価されることが保証されています1
ouah 2013年

3
@NikosC。いい質問ですね。これはの形式のコードにとって重要であり、if(foo == true)単に悪い習慣から完全なバグに移行します。
djechlin 2013年

1
の危険を指摘するための+1 (x == TRUE)は、とは異なる真理値を持つことができますx
Joshua Taylor

12

C ++(前述)以外に、静的分析ツールの利点もあります。コンパイラーは非効率性を排除しますが、静的アナライザーは独自の抽象型を使用して比較結果と他の整数型を区別できるため、TRUEは比較の結果である必要があり、互換性があるとは見なされないことを暗黙的に認識します整数で。

明らかにCは互換性があると言っていますが、バグを強調するためにその機能の意図的な使用を禁止することを選択することもできます-たとえば、誰かが混乱&している可能性があります&&。または、演算子の優先順位をぶつけました。


1
これは良い点であり、これらのツールのいくつかはif (boolean_var == TRUE) 、拡張によって愚かなコードを捕らえることさえできるかもしれません。拡張さif (boolean_var == (1 == 1))れた(1 == 1)ノードの型情報のおかげで、パターンに該当しますif (<*> == <boolean_expr>)
Kaz

4

実質的な違いはありません。0に評価されfalse1に評価されtrueます。ブール式1 == 1)またはを使用して1を定義trueしても、違いはありません。どちらもに評価されintます。

C標準ライブラリには、ブール値を定義するための特定のヘッダーが用意されていますstdbool.h


もちろん、あなたはそうではありません...しかし、特に負の数については、特にそうでないと考える人もいるでしょう:)
pinkpanther

何?あなたはそれを逆に持っています。 trueに評価され1falseに評価され0ます。Cはネイティブのブール型を知りません。それらは単なるintです。
djechlin 2013年

Cでは、関係演算子と等値演算子intは、値0or を使用したタイプの結果を生成します1。Cは、実際のboolean型を(持っている_Boolマクロで、boolで定義されている<stdbool.h>が、唯一なかったC99、で追加されたものではない新しいタイプを使用する事業者の意味を変更します。
キース・トンプソン

@djechlin:1999標準の時点で、Cにネイティブのブール型があります。それは呼ばれています_Boolし、<stdbool.h>持っています#define bool _Bool
キース・トンプソン

@KeithThompson、あなたは1 == 1として評価されることについて正しいですint。編集。

3

TRUEと等しい正確な値はわかりません。コンパイラは独自の定義を持つことができます。したがって、コンパイラーの内部のものを定義に使用することが優先されます。これは、良いプログラミングの習慣がある場合は必ずしも必要ではありませんが、次のような不適切なコーディングスタイルの問題を回避できます。

if((a> b)== TRUE)

これは、手動でTRUEを1と定義すると、災害になる可能性がありますが、TRUEの内部値は別の値です。


Cでは、>演算子は常にtrueの場合は1、falseの場合は0を返します。Cコンパイラがこれを間違っている可能性はありません。等価比較にTRUEFALSE貧弱なスタイルです。上記はより明確に書かれていif (a > b)ます。しかし、異なるCコンパイラが真と偽を異なる方法で処理できるという考えは、正しくありません。
キース・トンプソン

2
  1. リストアイテム

通常、Cプログラミング言語では、1はtrueとして定義され、0はfalseとして定義されます。したがって、次のことがよく見られる理由:

#define TRUE 1 
#define FALSE 0

ただし、条件文では、0以外の数値もtrueと評価されます。したがって、以下を使用することにより:

#define TRUE (1==1)
#define FALSE (!TRUE)

falseをtrueでないものと等しくすることで、安全に再生しようとしていることを明示的に示すことができます。


4
私はそれを「安全にプレイする」とは呼びません-むしろ、あなたは自分自身に誤った安心感を与えています。
dodgethesteamroller
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.