C ++演算子での暗黙の型変換規則


167

いつキャストすればいいのかよく知りたいです。追加、乗算などの際のC ++の暗黙の型変換規則は何ですか。たとえば、

int + float = ?
int * float = ?
float * int = ?
int / float = ?
float / int = ?
int / int = ?
int ^ float = ?

他...

式は常により正確な型として評価されますか?ルールはJavaで異なりますか?この質問の文言が不正確だった場合は訂正してください。


16
^XOR であることに注意してください。
GManNickG

16
@int ^ float =コンパイルエラー:)
Serge Dundich

回答:


223

C ++では、演算子(PODタイプの場合)は常に同じタイプのオブジェクトに作用します。
したがって、それらが同じでない場合、一方が他方と一致するように昇格されます。
演算結果の型はオペランド(変換後)と同じです。

If either is      long          double the other is promoted to      long          double
If either is                    double the other is promoted to                    double
If either is                    float  the other is promoted to                    float
If either is long long unsigned int    the other is promoted to long long unsigned int
If either is long long          int    the other is promoted to long long          int
If either is long      unsigned int    the other is promoted to long      unsigned int
If either is long               int    the other is promoted to long               int
If either is           unsigned int    the other is promoted to           unsigned int
If either is                    int    the other is promoted to                    int
Both operands are promoted to int

注意。操作の最小サイズはですint。したがって、short/ charint操作が完了する前に昇格されます。

すべての式で、操作が実行される前にintがに昇格さfloatれます。操作の結果はfloatです。

int + float =>  float + float = float
int * float =>  float * float = float
float * int =>  float * float = float
int / float =>  float / float = float
float / int =>  float / float = float
int / int                     = int
int ^ float =>  <compiler error>

1
「操作の最小サイズはintです。」-これは非常に奇妙です(char / short操作を効率的にサポートするアーキテクチャーについてはどうですか?)これは本当にC ++仕様にありますか?
ラファウDowgird

3
@ラファル:はい。intは、特定のプラットフォームでの操作に最も効率的な整数型であると想定されています。charは常に1でなければなりませんが、shortはintと同じサイズにすることができます。
マーティンヨーク

1
@Rafał:はい、それは非常に奇妙で、標準にあります。多くの場合、あなたが説明するアーキテクチャは、その非常に効率的なcharタイプを使用できます。の値char + charがに割り当てられているchar場合は、算術演算を実行しcharて、たとえばラップアラウンドすることができます。しかし、結果がに割り当てられている場合はint、それがより大きい場合に正しい結果を得るのに十分な大きさの型で算術を実行する必要がありますCHAR_MAX
Steve Jessop、2011

2
intがunsigned intに昇格されるという事実を強調したいだけです!!! 私は何日もバグに苦労してきました。負の結果が発生してもアンダーフローやラップアラウンドが発生しないように、両方がintまたはlongに昇格されるという印象を受けたからです。
nitsas 2013

10
問題の例「int型はunsigned int型に昇格ます」:((int) 4) - ((unsigned int) 5)になります429496729532ビットのint型と32ビット符号なし整数型のため。
nitsas 2013

33

float結果が含まれる算術演算の結果はfloatです。

int + float = float
int * float = float
float * int = float
int / float = float
float / int = float
int / int = int

詳細な回答については。C ++標準の§5/ 9セクションが言っていることを見てください

算術型または列挙型のオペランドを期待する多くの二項演算子は、変換を引き起こし、同様の方法で結果型を生成します。目的は、結果のタイプでもある一般的なタイプを生成する ことです。

このパターンは通常の算術変換と呼ばれ、次のように定義されます。

—どちらかのオペランドがlong double型の場合、もう一方はlong doubleに変換されます。

—そうでない場合、一方のオペランドがdoubleの場合、もう一方はdoubleに変換されます。

—それ以外の場合、一方のオペランドが浮動小数点数の場合、もう一方は浮動小数点数に変換されます。

—それ以外の場合、整数の昇格(4.5)は両方のオペランドに対して実行されます。54)

—次に、一方のオペランドがunsigned longの場合、もう一方はunsigned longに変換されます。

それ以外の場合、一方のオペランドがlong intでもう一方がunsigned intであり、long intがunsigned intのすべての値を表すことができる場合、unsigned intはlong intに変換されます。そうでない場合、両方のオペランドはunsigned long intに変換されます。

—そうでない場合、一方のオペランドがlongの場合、もう一方はlongに変換されます。

—そうでない場合、一方のオペランドが符号なしの場合、もう一方は符号なしに変換されます。

[注:それ以外の場合、残っている唯一のケースは、両方のオペランドがintである場合です]


3
...他のタイプがdoubleでもでもない限りlong double
CBベイリー

1
@チャールズ:正解。さらに明確にするために、標準から関連セクションを引用しました。
Nawaz

では、整数は常にデータを失うことなく浮動小数点に変換できますか?(例えば、指数をゼロにし、仮数にすべてを使用することによって)?
マルコA.

1
この回答は古くなっています。更新を提案します。特に、long longおよびunsigned long右ここでは取り上げません。
chux-モニカを2016年

@MarcoA。32ビットでfloatは、32ビットの仮数部に十分なビット(IEEE-754の場合は24ビット)intがないため、データが失われる可能性があります。64ビットでdouble十分です。
Mark Ransom

17

他の答えはC ++ 11の規則について話していないので、ここに1つあります。C ++ 11標準(ドラフトn3337)§5/ 9(違いを強調)から:

このパターンは通常の算術変換と呼ばれ、次のように定義されます。

—いずれかのオペランドがスコープ付き列挙型である場合、変換は実行されません。他のオペランドが同じ型でない場合、式の形式は正しくありません。

—どちらかのオペランドがlong double型の場合、もう一方はlong doubleに変換されます。

—そうでない場合、一方のオペランドがdoubleの場合、もう一方はdoubleに変換されます。

—それ以外の場合、一方のオペランドが浮動小数点数の場合、もう一方は浮動小数点数に変換されます。

—それ以外の場合、整数の昇格は両方のオペランドで実行されます。次に、昇格されたオペランドに次のルールが適用されます。

—両方のオペランドが同じタイプの場合、それ以上の変換は必要ありません。

—そうでない場合、両方のオペランドが符号付き整数型または両方が符号なし整数型を持つ場合、整数変換ランクの小さいタイプのオペランドは、ランクの大きいオペランドのタイプに変換されます。

—それ以外の場合、符号なし整数型のオペランドのランクが他のオペランドの型のランク以上である場合、符号付き整数型のオペランドは、符号なし整数型のオペランドの型に変換されます。

—それ以外の場合、符号付き整数型のオペランドの型が符号なし整数型のオペランドの型のすべての値を表すことができる場合、符号なし整数型のオペランドは符号付き整数型のオペランドの型に変換されます。

—そうでない場合、両方のオペランドは、符号付き整数型のオペランドの型に対応する符号なし整数型に変換されます。

頻繁に更新されるリストについては、こちらをご覧ください。


1
これらのルールは、C ++ 11で追加されたスコープ付き列挙型を除いて、C ++のすべてのバージョンで同じでした
MM

6

この回答は、主に@RafałDowgirdのコメントに向けられています。

「操作の最小サイズはintです。」-これは非常に奇妙です(char / short操作を効率的にサポートするアーキテクチャーについてはどうですか?)これは本当にC ++仕様にありますか?

C ++標準には非常に重要な「as-if」ルールがあることに注意してください。セクション1.8:プログラムの実行を参照してください。

3)この規定は、「as-if」ルールと呼ばれることもあります。これは、観察可能な結果から判断できる限り、実装は、結果が要件に準拠しているかのようである限り、標準の要件を無視してかまわないためです。プログラムの動作。

int標準では16ビットの最小値が義務付けられているため、最速の場合でも、コンパイラはを8ビットのサイズに設定できませんint

したがって、超高速の8ビット演算を備えた理論上のコンピュータの場合、int算術演算への暗黙の昇格が重要になる可能性があります。ただし、多くの操作では、コンパイラーが実際にanの精度で操作を行ってから変数に格納intするためにa charに変換したのか、それともすべての操作がcharで行われたのかがわかりません。

たとえばunsigned char = unsigned char + unsigned char + unsigned char、加算がオーバーフローするを考えます(それぞれの値を200と仮定しましょう)。に昇格した場合int、600が得られます。これは暗黙的ににキャストされ、unsigned char256を法としてラップされ、最終的な結果は88になります。そのような昇格を行わなかった場合は、最初の2つの追加により、問題がから200 + 200 + 200144 + 200、つまり344から88に減少します。つまり、プログラムは違いを認識しないためint、オペランドによりも低いランキングint

これは、加算、減算、乗算の一般に当てはまります。除算や係数については、一般的には当てはまりません。


4

符号なしの型を除外する場合、順序付きの階層があります。signedchar、short、int、long、long long、float、double、long double。まず、上記のintの前に来るものはすべてintに変換されます。次に、2項演算では、ランクの低い型が上位の型に変換され、結果は上位の型になります。(階層から、浮動小数点と整数型が関係する場合は常に、整数型は浮動小数点型に変換されることに注意してください。)

符号なしは少し複雑になります:ランキングを混乱させ、ランキングの一部は実装定義になります。このため、同じ式で符号付きと符号なしを混在させないことをお勧めします。(ほとんどのC ++エキスパートは、ビット単位の演算が含まれていない限り、符号なしを避けているようです。それが、少なくともStroustrupが推奨していることです。)


3
Stroustrupは彼が好きなものを推奨することができintますが、負になる必要がない数字に符号可能を使用すると、使用可能な範囲の完全な50%を完全に無駄にします。私は確かにStroustrupではありませんがunsigned、デフォルトでsigned、理由がある場合にのみ使用します。
underscore_d 2015

1
それはあなたが減算しなければならない日まで、アンダースコア_d、すべてうまくいきます。C ++の符号なし数値の主な問題は、減算を実行すると、符号なしのままになることです。したがって、std :: vectorが正しいかどうかを確認する関数を作成するとします。あなたは書くかもしれないbool in_order(vector<T> vec) { for ( int i = 0; i < size() - 1; ++i) { if (vec[i + 1] < vec[i]) return false; } return true;と、あなたは、サイズ()ので、それは空のベクトルのためにクラッシュしたことを見つけるために悩まされるだろう- 1を返す18446744073709551615.
jorgbrown

3

私の解決策問題が WA(間違った答え)だ、私は次のいずれかに変更intするとlong long int、それが与えたAC(受け入れを)。以前、私はしようとしましたlong long int += int * int、そして私がそれを修正した後long long int += long long int * int。私が思いついたグーグル、

1. 算術変換

型変換の条件:

満たされた条件--->変換

  • どちらのオペランドもlong doubleです。--->他のオペランドはlong double型に変換されます。

  • 先行条件が満たされておらず、どちらのオペランドもdouble型です。--->他のオペランドはdouble型に変換されます。

  • 先行する条件が満たされておらず、どちらのオペランドもfloat型です。--->他のオペランドはfloat型に変換されます。

  • 先行条件が満たされていません(どのオペランドも浮動小数点型ではありません)。--->整数昇格は、次のようにオペランドで実行されます。

    • いずれかのオペランドがunsigned long型である場合、もう一方のオペランドはunsigned long型に変換されます。
    • 上記の条件が満たされていない場合、およびいずれかのオペランドがlong型で、もう一方がunsigned int型である場合、両方のオペランドがunsigned long型に変換されます。
    • 上記の2つの条件が満たされておらず、いずれかのオペランドがlong型である場合、他のオペランドはlong型に変換されます。
    • 上記の3つの条件が満たされておらず、一方のオペランドがunsigned int型である場合、もう一方のオペランドはunsigned int型に変換されます。
    • 上記の条件がいずれも満たされない場合、両方のオペランドがint型に変換されます。

2。整数変換規則

  • 整数プロモーション:

intより小さい整数型は、それらに対して演算が実行されるときに昇格されます。元の型のすべての値がintとして表現できる場合、小さい方の型の値はintに変換されます。それ以外の場合は、unsigned intに変換されます。整数の昇格は、特定の引数式への通常の算術変換の一部として適用されます。単項+、-、および〜演算子のオペランド。およびシフト演算子のオペランド。

  • 整数変換ランク:

    • 同じ表現であっても、2つの符号付き整数型が同じランクを持つことはありません。
    • 符号付き整数型のランクは、精度の低い任意の符号付き整数型のランクよりも高くなります。
    • ランクがlong long intランクよりも大きくなければならないlong intのランクよりも大きくなければならない、intのランクよりも大きくなければならない、short intのランクよりも大きくなければなりません、signed char
    • 符号なし整数型のランクは、対応する符号付き整数型のランクと同じです(存在する場合)。
    • 標準整数型のランクは、同じ幅の拡張整数型のランクより大きくなければなりません。
    • のランクはcharsigned charおよびのランクと等しくなりunsigned charます。
    • 同じ精度を持つ別の拡張符号付き整数型と比較した拡張符号付き整数型のランクは、実装によって定義されますが、整数変換ランクを決定するための他の規則に従います。
    • すべての整数型T1、T2、およびT3について、T1がT2よりもランクが高く、T2がT3よりもランクが高い場合、T1はT3よりもランクが高くなります。
  • 通常の算術変換:

    • 両方のオペランドが同じタイプの場合、それ以上の変換は必要ありません。
    • 両方のオペランドが同じ整数型(符号付きまたは符号なし)である場合、整数変換ランクの小さいタイプのオペランドは、ランクの大きいオペランドのタイプに変換されます。
    • 符号なし整数型のオペランドのランクが他のオペランドの型のランク以上である場合、符号付き整数型のオペランドは、符号なし整数型のオペランドの型に変換されます。
    • 符号付き整数型のオペランドの型が、符号なし整数型のオペランドの型のすべての値を表すことができる場合、符号なし整数型のオペランドは、符号付き整数型のオペランドの型に変換されます。
    • それ以外の場合、両方のオペランドは、符号付き整数型のオペランドの型に対応する符号なし整数型に変換されます。特定の演算により、通常の算術演算のセマンティクスを追加または変更できます。

1

第4章全体で変換について説明していますが、主にこれらに興味があるはずです。

4.5整数のプロモーション [conv.prom]
char、signed char、unsigned char、short int、またはunsigned short intの右辺値は、intがソースタイプのすべての値を表すことができる場合、int型の右辺値に変換できます。それ以外の
場合は、ソースの右辺値をunsigned int型の右辺値に変換できます。
タイプwchar_t(3.9.1)または列挙型(7.2)の右辺
値は、基礎となるタイプのすべての値を表すことができる次のタイプの最初の右辺値に変換できます:int、unsigned int、
long、またはunsigned長いです。
整数ビットフィールド(9.6)の右辺値は、intが
ビットフィールドのすべての値を表すことができる場合、int型の右辺値に変換できます。それ以外の場合、unsigned intがrep-を実行できる場合は、unsigned intに変換できます。
ビットフィールドのすべての値を再送信します。ビットフィールドがまだ大きい場合は、統合的なプロモーションは適用されません。
ビットフィールドに列挙型がある場合、それはプロモーション目的でその型の他の値として扱われます。
bool型の右辺値は、int型の右辺値に変換でき、falseはゼロになり、true
は1になります。
これらの変換は、統合プロモーションと呼ばれます。

4.6浮動小数点の昇格 [conv.fpprom]
float型の右辺値はdouble型の右辺値に変換できます。値は変更されていません。
この変換は、浮動小数点昇格と呼ばれます。

したがって、floatを含むすべての変換-結果はfloatです。

両方のintを含むもののみ-結果はintです:int / int = int


1

式のタイプは、両方の部分が同じタイプでない場合、両方の最大のものに変換されます。ここでの問題は、どちらが大きいかを理解することです(バイト単位のサイズとは関係ありません)。

実数と整数が関係する式では、整数は実数に昇格されます。たとえば、int + floatでは、式のタイプはfloatです。

その他の違いは、型の機能に関連しています。たとえば、intとlong intを含む式は、long int型になります。


2
本当じゃない。一部のプラットフォームでlongは、a はa よりも「大きい」が、+ floatのタイプは何ですか。longfloat
CBベイリー

1
-1:最大とはどういう意味ですか?float はint より大きいですか?またはその逆
ポールR

2
コメントしてくださってありがとうございます。はい、ここではバイト単位のサイズはまったく関係ありません。明らかに、イタリック体を最大にしても、答えを説明するには不十分です。とにかく、他にも非常に徹底した答えがあるので、それをもっと深く説明することは意味がありません。
Baltasarq 2011

-2

警告!

変換は左から右に行われます。

これを試して:

int i = 3, j = 2;
double k = 33;
cout << k * j / i << endl; // prints 22
cout << j / i * k << endl; // prints 0

9
これは、変換のためではなく、演算子の優先順位のためです。j + i * k結果は101になります
。– gartenriese
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.