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


133

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?

三項演算子はbooleanタイプを返し、sizeof boolタイプは1Cのバイトです。

では、なぜsizeof(a ? true : false)4バイトの出力が得られるのでしょうか。


39
sizeof(true)そしてsizeof(false)また、4:ide.geeksforgeeks.org/O5jvuN
tkausl

7
ここでさらに興味深い質問は、この実装が_Boolサイズ1を持つことを明らかに定義しているが、trueand ではないという点で、この実装が「一貫性がない」理由falseです。しかし、私が知る限り、規格にはそれについて何も言うことはありません。

12
@FelixPalmenが与えられたのchar a; sizeof(a) == 1と同じ理由とsizeof('a') == sizeof(int)(Cで)。それは実装についてではなく、言語についてです。
n。「代名詞」m。

10
印刷してみましたsizeof(true)か?多分それはシンをもう少し明確にするでしょう(特に、三項演算子が赤いニシンであることが明らかになるでしょう)。
n。「代名詞」m。

4
@FelixPalmen true#define1であるstdbool.hので、はい、これは文字通りの定義です。
n。「代名詞」m。

回答:


223

あなたが持っているからです#include <stdbool.h>。そのヘッダの定義マクロ truefalseなるように10、ので、このようなあなたの文のルックス:

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

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


21
「#include <stdbool.h>があるからです」いいえ、ありません。sizeof(a ? (uint8_t)1 : (uint8_t)0);また、結果は4 ?:trueなりfalseます。ここでは、オペランドの整数の昇格が重要な部分であり、and のサイズではありません。
ランディン2017年

9
@Lundin:どちらも重要です。書かれているとおり、このタイプはすでにint昇格されていません。これを「修正」できない理由は、デフォルトのプロモーションです。
R .. GitHub ICEのヘルプの停止

5
@PeterSchneiderこれはC ++ではありません。これはCです。C++では、マクロtruefalseはありません。それらはキーワードです。これらは1および0として定義されていませんが、bool型の真と偽の値として定義されています。
ジャスティン

5
@PeterSchneiderいいえ、あなたは今日Cについて何かを学びました。2つの言語を混同しないでください。C ++では、sizeof(true)1です。demo
Rakete1111 2017年

1
確かに、混乱しています。注意深く読んでおらず、cppreference-linkによって誤解を招きました。私のせいで、ありがとう。しかし、私はとにかくc ++についてのこの感覚を持っています。
Peter Schneider

66

ここでは、3項演算子の戻り値のboolean型、

OK、それだけではありません!

Cでは、この 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)真に標準に準拠しているべきです。


@ user694733 umm ..どうしてですか?<stdbool.h>MACROSのタイプをint..と定義しています。それは間違っていますか?
Sourav Ghosh 2017

@BasileStarynkevitch OK、わかりました。これは確かに間違っているようです。更新されました。
Sourav Ghosh 2017

58

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

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

4(またはsizeof(int)プラットフォームにあるもの)を出力します。

以下は、boolcharサイズ1の同義語または同様のタイプであり、intより大きいことを前提としていcharます。

sizeof(true) != sizeof(bool)sizeof(true) == sizeof(int)が単純な理由である理由は、型の式でtrueないためですbool。タイプの表現ですint。それはさ#defineをd 1の中でstdbool.h

boolCにはタイプの右辺値はまったくありません。そのようなすべての右辺値はint、への引数として使用された場合でも、すぐにに昇格されますsizeof編集:この段落は真実ではありsizeofませんint。ただし、これは結論には影響しません。


素敵な答え。現在最も支持されている回答を読んだ後、すべてのステートメントが4に評価されるはずだと考えていました。これで問題が解決しました。+1
ペドロA

5
(bool)1タイプの右辺値ではありませんboolか?
Ben Voigt 2017年

printf("%u\n", sizeof((char) 1));1私のプラットフォームで印刷するのに対し、printf("%u\n", sizeof(1));印刷し4ます。これは、「sizeofの引数として使用されている場合でも、そのようなすべての右辺値が直ちにintに昇格される」という文が偽であることを意味しませんか?
JonatanE 2017年

これは実際には質問の答えにはなりません。などのサイズとタイプはtrue実際には問題ではありません?:intとにかく整数に昇格されるので。つまり、答えは、なぜ ?:赤ニシンであるかを説明する必要があります。
ランディン2017年

6
答えは可能な限り最善の方法で問題に対処すると思います。反対投票や改善を歓迎します。
n。「代名詞」m。

31

Cのブール型について

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

アプリケーションのようなホームメイドタイプを使用することが習慣だったtypedef enum { FALSE, TRUE } BOOL;にもつまるところ、int-sized種類。

C ++にははるかに優れた明示的なブール型boolがあり、1バイト以下でした。Cのブール型またはブール式は、最悪の場合4バイトになります。C ++との互換性のある方法は、C99標準でCに導入されました。Cはブール型_Boolとヘッダーも取得しましたstdbool.h

stdbool.hC ++との互換性を提供します。このヘッダーは、小さな整数型であり、おそらく1バイト大きい型にbool展開されるマクロ(C ++キーワードと同じスペル)を定義し_Boolます。同様に、ヘッダーは2つのマクロを提供しますtrueおよびをfalseスペルはC ++キーワードと同じですが、古いCプログラムとの下位互換性があります。したがって、truefalseに拡大1し、0Cに、そのタイプがありますint。これらのマクロは、実際には対応するC ++キーワードのようにブール型ではありません。

同様に、下位互換性のために、Cの論理演算子 int、今日ではCがブール型になっているにもかかわらず、今でもを返します。C ++では、論理演算子はを返しますbool。したがってこのような表現は、sizeof(a == b)のサイズ与えるintCで、しかしのサイズboolC ++です。

条件演算子について ?:

条件演算子?:は、いくつかの癖がある奇妙な演算子です。100%と同等であると考えるのはよくある間違いif() { } else {}です。結構です。

1番目と2番目または3番目のオペランドの評価の間にシーケンスポイントがあります。?:オペレータは、それが評価されていないオペランドのいずれかの副作用を実行することができないので、第二または第三のオペランドのいずれかのみを評価することが保証されます。のようなコードtrue? func1() : func2()は実行されませんfunc2()。ここまでは順調ですね。

ただし通常の算術変換では、第2オペランドと第3オペランドが暗黙的に型昇格され、相互にバランスを取る必要があることを示す特別なルールがあります。(ここで説明するCの暗黙的な型の昇格規則)。つまり、2番目または3番目のオペランドは常に少なくともと同じ大きさになりintます。

それは問題ではありません。それはそうtrueと、falseたまたまintC の型であるので、式は常に少なくともint問題のサイズを提供します。

式を書き換えて も、サイズは返されますsizeof(a ? (bool)true : (bool)false) int !のます。

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


1
C ++は実際には保証しませんsizeof(bool)==1
aschepler 2017年

1
@ascheplerいいえ。ただし、C ++標準以外の現実では保証されています。1でないコンパイラを1つ挙げてください
。– Lundin

こんにちは。私はこの答えは良いだろうと考えずにその最初の部分。2番目の部分は質問に答えます。残りは面白いですが、ただのノイズです。
YSC 2018

@YSCこれは元々CとC ++の両方でタグ付けされていたため、それらの異なるブール型とそれらの背後にある履歴との比較が必要でした。C ++タグがなければ、最初の部分を書いたとは思えません。しかし、一つははsizeof(ブール値)はCで1が、はsizeof(偽)である4である理由を理解する必要があります
ランディン

21

素早い回答:

  • sizeof(a ? true : false)と評価される4理由はtrue、とfalseはそれぞれとで定義さ<stdbool.h>10いるため、式は、プラットフォームで4バイトを占有sizeof(a ? 1 : 0)するtypeの整数式であるに展開さintれます。同じ理由で、システムでsizeof(true)も評価さ4れます。

ただし、次のことに注意してください。

  • sizeof(a ? a : a)また4、3項演算子が整数式である場合、3番目の演算子が2番目と3番目のオペランドで整数の昇格を実行するため、は評価されます。もちろん同じことがsizeof(a ? true : false)and sizeof(a ? (bool)true : (bool)false)でも起こりますが、式全体をキャストboolすると期待どおりに動作しますsizeof((bool)(a ? true : false)) -> 1

  • また、比較演算子はブール値1orまたはに評価されます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()式はすべて1C ++で評価されます。


2
オペランドは整数に昇格されるため、どのようなタイプtruefalseあるかは問題ではないことを実際に指摘することができる良い答えです。したがって、結果として4も得られます。?:intsizeof(a ? (uint8_t)true : (uint8_t)false)
ランディン2017年

この回答は、重要なポイント、つまり昇進する価値をカバーしていますint
Chinni 2017年

1

これは、ソースに含まれているスニペットです

#ifndef __cplusplus

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

#else /* __cplusplus */

マクロがありtruefalseそれぞれ1および0として宣言されています。

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

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


-3

Cにはブールデータ型はありません。代わりに、論理式は1trueの場合は整数値に評価されます0

条件式が好きifforwhile、またはc ? a : b数は、それは考えられていますゼロでない場合、整数を期待してtrue、いくつかの特別な場合を除き、ここでは三項演算子は評価するする再帰関数sumだtrueまでn届きます0

int sum (int n) { return n ? n+sum(n-1) : n ;

またNULL、ポインターのチェックにも使用できます。Singly-Linked-Listの内容を出力する再帰関数を次に示します。

void print(sll * n){ printf("%d -> ",n->val); if(n->next)print(n->next); }
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.