web-dev-qa-db-ja.com

なぜ「sizeof(a?true:false)」が4バイトの出力になるのですか?

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バイトの出力を出すのですか?

130
msc

#include <stdbool.h>があるからです。そのヘッダー マクロを定義するtruefalse10になるので、あなたの文は次のようになります。

printf("%zu\n", sizeof(a ? 1 : 0)); // Why 4?

あなたのプラットフォームではsizeof(int)は4です。

224
Justin

ここで、三項演算子は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)であるべきです。

67
Sourav Ghosh

三項演算子は赤いニシンです。

    printf("%zu\n", sizeof(true));

4(またはあなたのプラットフォームにあるsizeof(int)が何か)を表示します。

以下は、boolcharまたは同種のサイズ1であり、intcharよりも大きいことを前提としています。

sizeof(true) != sizeof(bool)sizeof(true) == sizeof(int)が単にtrueではないbool型の式であることが理由です。これはint型の式です。 #define1と同じstdbool.hdです。

Cにはbool型の右辺値はまったくありません。そのようなすべての右辺値は、intの引数として使用されていても、直ちにsizeofに昇格されます。 編集:この段落は真実ではない、sizeofへの引数はintに昇格されません。これは結論には影響しません。

58
n.m.

Cのブール型について

ブール型はC言語のかなり後の1999年に導入されました。それ以前は、Cにはブール型がなく、すべてのブール式にintが使用されていました。したがって、> == !などのすべての論理演算子は、値1または0intを返します。

アプリケーションが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でtruefalseがたまたまタイプintであることは問題ではありません。なぜなら式は常に少なくともintのサイズを与えるからです。

式を書き換えてもsizeof(a ? (bool)true : (bool)false)それでもサイズを返しますint

これは、通常の算術変換による暗黙的な型昇格のためです。

30
Lundin

素早い回答:

  • sizeof(a ? true : false)4に評価されます。これは、truefalse<stdbool.h>でそれぞれ10として定義されているため、式が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に評価します。

21
chqrlie

これが、ソースに含まれているものです。

#ifndef __cplusplus

#define bool    _Bool
#define true    1
#define false   0

#else /* __cplusplus */

マクロtruefalseはそれぞれ1と0として宣言されています。

ただしこの場合、型はリテラル定数の型です。 0と1はどちらもintに収まる整数定数なので、その型はintです。

そしてあなたの場合のsizeof(int)は4です。

1
u__