C ++でのシフト操作後に、ビットフィールドのunsignedintがsignedintになるのはなぜですか?[複製]
テストコード:
struct A
{
uint32_t lo : 16;
uint32_t hi : 16;
};
int main()
{
A a{};
a.lo = 0xFFFF;
auto b = a.lo << 16;
cout << b << endl;
return 0;
}
出力は:-65536
であり、のタイプはb
ですint
がuint32_t
。ではありません。
私はそれを見つけました、uint16_t
そしてuint8_t
またシフト演算子の後にsigned intになります、そして同様の質問がありました、そしてそれはC#
オペランドが<32ビットであるとき結果がsignedになるという結論に達しました。オペランドが32ビット未満の場合、シフト演算が常に符号付き整数になるのはなぜですか
しかし、のタイプa.lo
は明確uint32_t
でありdecltype(a.lo)
、によって確認できます。これはどのように説明できますか?
回答
これは、標準の汎整数拡張の一部です。
[expr.shift]
1シフト演算子
<<
と>>
グループを左から右にオペランドは、整数型またはスコープなしの列挙型であり、整数の昇格が実行されます。結果のタイプは、プロモートされた左オペランドのタイプです。
[conv.prom]
5整数ビットフィールド([class.bit])のprvalueは、ビットフィールドのすべての値を表すことができる
int
場合、タイプのprvalueに変換できますint
。それ以外の場合は、ビットフィールドのすべての値を表すことができるunsigned int
ifに変換unsigned int
できます。ビットフィールドがまだ大きい場合、汎整数拡張は適用されません。ビットフィールドに列挙型がある場合、プロモーションの目的でその型の他の値として扱われます。
左のオペランド(ビットフィールド)を昇格すると、が生成されるint
ため、これがシフト式全体のタイプです。したがって、b
あるint
プレースホルダ型推論によってすぎ。