22

が C++11 にunsigned short * unsigned short変換されるのはなぜですか?int

このintコード行で示されているように、 は小さすぎて最大値を処理できません。

cout << USHRT_MAX * USHRT_MAX << endl;

MinGW 4.9.2 でのオーバーフロー

-131071

なぜなら (ソース)

USHRT_MAX = 65535 (2^16-1) 以上*

INT_MAX = 32767 (2^15-1) 以上*

(2^16-1)*(2^16-1) = ~2^32


このソリューションに問題はありますか?

unsigned u = static_cast<unsigned>(t*t);

このプログラム

unsigned short t;
cout<<typeid(t).name()<<endl;
cout<<typeid(t*t).name()<<endl;

出力を与える

t
i

の上

gcc version 4.4.7 20120313 (Red Hat 4.4.7-16) (GCC)
gcc version 4.8.2 (GCC)
MinGW 4.9.2

両方と

g++ p.cpp
g++ -std=c++11 p.cpp

これは、これらのコンパイラt*tで に変換されることを証明しています。int


役立つリソース:

Cでの符号付きから符号なしへの変換 - 常に安全ですか?

符号付きおよび符号なし整数の乗算

https://bytes.com/topic/c-sharp/answers/223883-multiplication-types-smaller-than-int-yields-int

http://www.cplusplus.com/reference/climits

http://en.cppreference.com/w/cpp/language/types


編集:次の画像で問題を示しました。

ここに画像の説明を入力

4

6 に答える 6

14

あなたは暗黙の変換について読みたいと思うかもしれません.

小さな整数型の prvalue ( など)char)は、より大きな整数型 ( などint) の prvalue に変換される可能性があります。特に、算術演算子は、より小さい型intを引数として受け入れません。

上記が言っていることは、算術演算子(もちろん乗算を含む)を含む式でint( のような)より小さいものを使用すると、値は に昇格されるということです。unsigned shortint

于 2015-11-16T08:50:48.023 に答える
11

これは、通常の算術変換の実行です。

一般に引数昇格と呼ばれますが、標準ではその用語をより制限された方法で使用しています (合理的な記述用語と標準語の間の永遠の対立)。

C++11 §5/9:

算術型または列挙型のオペランドを期待する多くの二項演算子は、同様の方法で変換を行い、結果の型を生成します目的は、結果の型でもある共通の型を生成することです。このパターンは、通常の算術変換と呼ばれます […]

この段落では、すべての引数を表現できるようになるまで、より一般的な型のはしごを上る変換に相当する詳細について説明します。このはしごの最下位のラングは、2 項演算の両方のオペランドの整数昇格であるため、少なくとも実行されます (ただし、変換は上位のラングから開始できます)。そして、一体的なプロモーションはこれから始まります:

C++11 §4.5/1:

boolchar16_tchar32_t、またはwchar_t整数変換ランク (4.13) が のランクより小さい整数型のprvalueは、ソース型のすべての値を表すことができる場合int、型の prvalue に変換できます。それ以外の場合は、ソースの prvalue を型の prvalue に変換できますintintunsigned int

重要なことに、これは算術式ではなく型に関するものです。あなたの場合、乗算演算子の引数は に*変換されintます。次に、乗算が乗算として実行され、結果intが得られます。int

于 2015-11-16T08:55:49.980 に答える
6

コメントで Paolo M が指摘したように、USHRT_MAXタイプintを持っています (これは 5.2.4.2.1/1 で指定されています: そのようなマクロはすべて、少なくとも と同じ大きさのタイプを持っていますint)。

すでにxでUSHRT_MAX * USHRT_MAXあるため、プロモーションは発生しません。 intint

これにより、システムで符号付き整数のオーバーフローが発生し、未定義の動作が発生します。


提案された解決策について:

unsigned u = static_cast<unsigned>(t*t);

t*tこれは、符号付き整数のオーバーフローによる未定義の動作を引き起こすため、役に立ちません。他の回答で説明されているように、歴史的な理由から、乗算が発生する前にt昇格されます。int

代わりに、次を使用できます。

auto u = static_cast<unsigned int>(t) * t;

これは、整数の昇格後、 をunsigned int掛けたものintです。そして、残りの通常の算術変換に従って、intは に昇格しunsigned int、明確に定義された剰余乗算が発生します。

于 2015-11-16T10:00:14.563 に答える
5

整数昇格ルールあり

USHRT_MAX値が に昇格されintます。次に、2 int の乗算を行います (オーバーフローの可能性あり)。

于 2015-11-16T08:51:05.930 に答える
3

他の回答で指摘されているように、これは整数昇格ルールが原因で発生します。

ランクが大きい符号付きタイプよりランクが小さい符号なしタイプからの変換を回避する最も簡単な方法は、変換がunsigned intおよび ではないことを確認することintです。

これは、unsigned int 型の値 1 を掛けることによって行われます。1 は乗法恒等式であるため、結果は変更されません。

unsigned short c = t * 1U * t;

まず、オペランド t と 1U が評価されます。左オペランドは符号付きで、符号なしの右オペランドよりランクが小さいため、右オペランドの型に変換されます。次に、オペランドが乗算され、結果と残りの右側のオペランドで同じことが起こります。以下に引用する標準の最後の段落は、このプロモーションに使用されます。

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

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

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

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

于 2015-11-16T15:42:07.377 に答える