web-dev-qa-db-ja.com

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

いつキャストすべきかを知りたい。追加、乗算などを行うときのC++の暗黙の型変換規則は何ですか。たとえば、

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

など.

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

153
Matt Montag

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/charは、操作が完了する前にintに昇格されます。

すべての式で、操作が実行される前にintfloatに昇格されます。操作の結果は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>
201
Martin York

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に変換されます。

—それ以外の場合、一方のオペランドがfloatであれば、他方はfloatに変換されます。

—それ以外の場合、両方のオペランドで積分プロモーション(4.5)が実行されます。54)

—次に、一方のオペランドが符号なしlongの場合、他方は符号なしlongに変換されます。

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

—それ以外の場合、一方のオペランドが長い場合、他方はlongに変換されます。

—それ以外の場合、一方のオペランドが符号なしの場合、他方は符号なしに変換されます。

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

30
Nawaz

他の回答ではC++ 11のルールについて説明していないため、ここに1つあります。 C++ 11標準(ドラフトn3337)§5/ 9から:

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

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

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

—それ以外の場合、一方のオペランドがdoubleであれば、他方はdoubleに変換されます。

—それ以外の場合、一方のオペランドがfloatであれば、他方はfloatに変換されます。

—それ以外の場合、積分プロモーションは両方のオペランドで実行されます。次に、昇格されたオペランドに次の規則が適用されます。

—両方のオペランドの型が同じ場合、それ以上の変換は不要です。

—それ以外の場合、両方のオペランドに符号付き整数型があるか、両方に符号なし整数型がある場合、整数変換ランクが小さい型のオペランドは、ランクが大きいオペランドの型に変換されます。

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

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

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

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

16
legends2k

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

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

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

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

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

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

例えば、加算がオーバーフローするunsigned char = unsigned char + unsigned char + unsigned charを考えてみましょう(それぞれ200の値を想定しましょう)。 intに昇格すると、600が得られます。これは暗黙的にunsigned charにダウンキャストされ、256を法としてラップするため、88の最終結果が得られます。 、最初の2つの追加の間にラップする必要があります。これにより、問題が200 + 200 + 200から144 + 200(344)に減少し、88に減少します。つまり、プログラムはそのため、コンパイラーは、オペランドがintより低いランキングを持っている場合、intで中間操作を実行するという命令を自由に無視できます。

これは、加算、減算、および乗算の一般に当てはまります。一般に、除算またはモジュラスには当てはまりません。

5
David Stone

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

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

3
James Kanze

ソリューション に対する 問題 はWA(間違った答え)を取得し、intの1つをlong long intに変更し、 AC(accept) 。以前は、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のランクより大きくなければなりません。
    • 符号なし整数型のランクは、対応する符号付き整数型のランクがあればそれと等しくなります。
    • 標準整数型のランクは、同じ幅の拡張整数型のランクよりも大きくなければなりません。
    • charのランクは、signed charおよびunsigned charのランクと等しくなります。
    • 同じ精度を持つ別の拡張符号付き整数型に関連する拡張符号付き整数型のランクは、実装で定義されますが、整数変換ランクを決定するための他の規則に従います。
    • すべての整数タイプT1、T2、およびT3について、T1がT2よりもランクが大きく、T2がT3よりもランクが大きい場合、T1はT3よりもランクが大きくなります。
  • 通常の算術変換:

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

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

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

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

1
Baltasarq

第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 long。
intがすべてを表現できる場合、整数ビットフィールド(9.6)の右辺値は、int型の右辺値に変換できます。
ビットフィールドの値。それ以外の場合は、unsigned intが繰り返し可能な場合、unsigned intに変換できます。
ビットフィールドのすべての値を再送信します。ビットフィールドがまだ大きい場合、統合的なプロモーションは適用されません。もし
ビットフィールドには列挙型があり、昇格のためにその型の他の値として扱われます。
bool型の右辺値は、int型の右辺値に変換できます。falseはゼロになり、trueになります
1つになります。
これらのコンバージョンは、インテグラルプロモーションと呼ばれます。

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

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

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

1
BЈовић