標準からの関連する引用:
5 式 [expr]
10 算術型または列挙型のオペランドを期待する多くの二項演算子は、同様の方法で変換を行い、結果の型を生成します。目的は、結果の型でもある共通の型を生成することです。このパターンは通常の算術変換と呼ばれ、次のように定義されます。
[等号の種類または等号の種類に関する 2 節を省略]
— それ以外の場合、符号なし整数型を持つオペランドのランクが他のオペランドの型のランク以上である場合、符号付き整数型を持つオペランドは、符号なし整数型を持つオペランドの型に変換されます。
— それ以外の場合、符号付き整数型のオペランドの型が符号なし整数型のオペランドの型のすべての値を表すことができる場合、符号なし整数型のオペランドは符号付き整数型のオペランドの型に変換されます。
— それ以外の場合、両方のオペランドは、符号付き整数型のオペランドの型に対応する符号なし整数型に変換されます。
システム上のsizeof(int) < sizeof(long) == sizeof(long long)
上記の 3 つの節のそれぞれについて、次の 3 つの事例を考えてみましょう(他の事例に容易に適応可能) 。
#include <iostream>
signed int s1 = -4;
unsigned int u1 = 2;
signed long int s2 = -4;
unsigned int u2 = 2;
signed long long int s3 = -4;
unsigned long int u3 = 2;
int main()
{
std::cout << (s1 + u1) << "\n"; // 4294967294
std::cout << (s2 + u2) << "\n"; // -2
std::cout << (s3 + u3) << "\n"; // 18446744073709551614
}
出力付きのライブ例。
第 1 節: 等しいランクの型なので、signed int
オペランドは に変換されunsigned int
ます。これには、(2 の補数を使用して) 値を出力する値変換が伴います。
2 番目の句: 符号付き型はランクが高く、(このプラットフォームでは!) 符号なし型のすべての値を表すことができるため、符号なしオペランドは符号付き型に変換され、-2 を取得します。
3 番目の節: 符号付き型は再びランクが高くなりますが、(このプラットフォームでは!) 符号なし型のすべての値を表すことはできないため、両方のオペランドが に変換され、符号付きunsigned long long
オペランドの値変換の後、出力された値が得られます。
符号なしオペランドが十分に大きい場合 (たとえば、これらの例では 6)、符号なし整数のオーバーフローにより、最終結果は 3 つの例すべてで 2 になることに注意してください。
(追加) これらの型を比較すると、さらに予想外の結果が得られることに注意してください。上記の例 1 を<
次のように考えてみましょう。
#include <iostream>
signed int s1 = -4;
unsigned int u1 = 2;
int main()
{
std::cout << (s1 < u1 ? "s1 < u1" : "s1 !< u1") << "\n"; // "s1 !< u1"
std::cout << (-4 < 2u ? "-4 < 2u" : "-4 !< 2u") << "\n"; // "-4 !< 2u"
}
2u
はサフィックスunsigned
によって明示的に作成されるため、同じ規則が適用されます。そして、結果はおそらく、C++ での記述時に-4 < 2u
を比較したときに期待するものではありません...-4 < 2u