sizeof
演算子と三項演算子についての小さなコードがあります。
#include <stdio.h>
#include <stdbool.h>
int main()
{
bool a = true;
printf("%zu\n", sizeof(bool)); // Ok
printf("%zu\n", sizeof(a)); // Ok
printf("%zu\n", sizeof(a ? true : false)); // Why 4?
return 0;
}
出力( GCC ):
1
1
4 // Why 4?
しかし、ここで、
printf("%zu\n", sizeof(a ? true : false)); // Why 4?
cの3進演算子はboolean
typeを返し、sizeof bool
typeは1
バイトです。
では、なぜsizeof(a ? true : false)
は4バイトの出力を出すのですか?
#include <stdbool.h>
があるからです。そのヘッダー マクロを定義するtrue
とfalse
は1
と0
になるので、あなたの文は次のようになります。
printf("%zu\n", sizeof(a ? 1 : 0)); // Why 4?
あなたのプラットフォームではsizeof(int)
は4です。
ここで、三項演算子は
boolean
型を返します、
それでは、他にもあります。
Cでは、this 3項演算の結果はint
型になります。 [下記の注意事項(1,2)]
したがって、プラットフォーム上での結果は式sizeof(int)
と同じです。
注1:C11
の引用、§7.18、Boolean type and values <stdbool.h>
[....]残りの3つのマクロは
#if
前処理指令での使用に適しています。彼らです
true
これは整数定数1に展開されます。
false
これは整数定数0に展開されます。
注2:条件付き演算子については、§6.5.15、(は私の主張を強調する)
最初のオペランドが評価されます。その評価と2番目または3番目のオペランドの評価(どちらか評価される方)の間にシーケンスポイントがあります。 2番目のオペランドは、最初のオペランドが0と等しくない場合にのみ評価されます。 3番目のオペランドは、最初のオペランドが0に等しい場合にのみ評価されます。 結果は2番目または3番目のオペランドの値になります(どちらが評価されても)、 [...]
そして
2番目と3番目のオペランドの両方に算術型がある場合、それら2つのオペランドに適用された場合、通常の算術変換によって決定される結果型が結果の型になります。 [... ]
したがって、結果は整数型になり、値の範囲のため、定数は正確にint
型になります。
そうは言っても、一般的なアドバイス、int main()
は本当に標準に準拠するためにはint main (void)
であるべきです。
三項演算子は赤いニシンです。
printf("%zu\n", sizeof(true));
4(またはあなたのプラットフォームにあるsizeof(int)
が何か)を表示します。
以下は、bool
がchar
または同種のサイズ1であり、int
がchar
よりも大きいことを前提としています。
sizeof(true) != sizeof(bool)
とsizeof(true) == sizeof(int)
が単にtrue
がではないbool
型の式であることが理由です。これはint
型の式です。 #define
の1
と同じstdbool.h
dです。
Cには 編集:この段落は真実ではない、bool
型の右辺値はまったくありません。そのようなすべての右辺値は、int
の引数として使用されていても、直ちにsizeof
に昇格されます。sizeof
への引数はint
に昇格されません。これは結論には影響しません。
Cのブール型について
ブール型はC言語のかなり後の1999年に導入されました。それ以前は、Cにはブール型がなく、すべてのブール式にint
が使用されていました。したがって、> == !
などのすべての論理演算子は、値1
または0
のint
を返します。
アプリケーションがtypedef enum { FALSE, TRUE } BOOL;
などの自家製の型を使用することはカスタムであり、int
サイズの型にもなります。
C++には、より優れた明示的なブール型bool
があり、1バイト以下でした。 Cのブール型またはブール式は、最悪の場合4バイトになります。 C++との互換性のある方法がCにC99標準で導入されました。次に、Cはブール型の_Bool
とヘッダーstdbool.h
を取得しました。
stdbool.h
は、C++との互換性を提供します。このヘッダーは、_Bool
に展開されるマクロbool
(C++キーワードと同じスペル)を定義します。これは、1バイトの大きさの可能性がある小さな整数型です。同様に、ヘッダーには2つのマクロtrue
およびfalse
があり、C++キーワードと同じスペルただし、古いCプログラムとの下位互換性です。したがって、true
およびfalse
は、Cでは1
および0
に展開され、そのタイプはint
です。これらのマクロは、対応するC++キーワードのように実際にはブール型ではありません。
同様に、下位互換性のために、C stillの論理演算子は、今日のCがブール型を取得していても、今日までint
を返します。 C++では、論理演算子はbool
を返します。したがって、sizeof(a == b)
などの式は、Cではint
のサイズを示しますが、C++ではbool
のサイズを示します。
条件演算子?:
について
条件演算子?:
は、いくつかの癖がある奇妙な演算子です。 if() { } else {}
と100%同等であると考えるのはよくある間違いです。そうでもない。
第1オペランドと第2オペランドまたは第3オペランドの評価の間にシーケンスポイントがあります。 ?:
演算子は、2番目または3番目のオペランドのみを評価することが保証されているため、評価されないオペランドの副作用を実行することはできません。 true? func1() : func2()
のようなコードはfunc2()
を実行しません。ここまでは順調ですね。
ただし、通常の算術変換を使用して、2番目と3番目のオペランドを暗黙的に型昇格し、相互にバランスを取る必要があるという特別な規則があります。 ( ここで説明されているCの暗黙の型昇格規則 )。これは、第2または第3オペランドがalways少なくともint
と同じ大きさであることを意味します。
したがって、Cでtrue
とfalse
がたまたまタイプint
であることは問題ではありません。なぜなら式は常に少なくともint
のサイズを与えるからです。
式を書き換えてもsizeof(a ? (bool)true : (bool)false)
それでもサイズを返します(int
!
これは、通常の算術変換による暗黙的な型昇格のためです。
素早い回答:
sizeof(a ? true : false)
は4
に評価されます。これは、true
とfalse
が<stdbool.h>
でそれぞれ1
と0
として定義されているため、式がsizeof(a ? 1 : 0)
に展開されるためですプラットフォームで4バイトを占有するタイプint
の整数式。同じ理由で、sizeof(true)
もシステムで4
と評価されます。ただし、次のことに注意してください。
sizeof(a ? a : a)
も4
に評価されます。これは、三項演算子が整数式である場合、2番目と3番目のオペランドで整数プロモーションを実行するためです。もちろん、sizeof(a ? true : false)
とsizeof(a ? (bool)true : (bool)false)
についても同じことが起こりますが、式全体をbool
としてキャストすると、期待どおりに動作します:sizeof((bool)(a ? true : false)) -> 1
。
比較演算子はブール値1
または0
に評価されますが、int
タイプはsizeof(a == a) -> 4
であることに注意してください。
a
のブール値の性質を保持する唯一の演算子は次のとおりです。
コンマ演算子:sizeof(a, a)
とsizeof(true, a)
は両方とも、コンパイル時に1
と評価されます。
代入演算子:sizeof(a = a)
とsizeof(a = true)
の両方の値は1
です。
インクリメント演算子:sizeof(a++) -> 1
最後に、上記のすべてはCにのみ適用されます。C++には、bool
型、ブール値true
およびfalse
、比較演算子、三項演算子に関するさまざまなセマンティクスがあります:これらのsizeof()
式のすべてC++で1
に評価します。
これが、ソースに含まれているものです。
#ifndef __cplusplus
#define bool _Bool
#define true 1
#define false 0
#else /* __cplusplus */
マクロtrue
とfalse
はそれぞれ1と0として宣言されています。
ただしこの場合、型はリテラル定数の型です。 0と1はどちらもintに収まる整数定数なので、その型はintです。
そしてあなたの場合のsizeof(int)
は4です。