C ++でのシフト操作後に、ビットフィールドのunsignedintがsignedintになるのはなぜですか?[複製]

Dec 15 2020

テストコード:

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ですintuint32_t。ではありません。

私はそれを見つけました、uint16_tそしてuint8_tまたシフト演算子の後にsigned intになります、そして同様の質問がありました、そしてそれはC#オペランドが<32ビットであるとき結果がsignedになるという結論に達しました。オペランドが32ビット未満の場合、シフト演算が常に符号付き整数になるのはなぜですか

しかし、のタイプa.loは明確uint32_tでありdecltype(a.lo)、によって確認できます。これはどのように説明できますか?

回答

7 StoryTeller-UnslanderMonica Dec 15 2020 at 20:01

これは、標準の汎整数拡張の一部です。

[expr.shift]

1シフト演算子<<>>グループを左から右に

オペランドは、整数型またはスコープなしの列挙型であり、整数の昇格が実行されます。結果のタイプは、プロモートされた左オペランドのタイプです。

[conv.prom]

5整数ビットフィールド([class.bit])のprvalueは、ビットフィールドのすべての値を表すことができるint場合、タイプのprvalueに変換できますint。それ以外の場合は、ビットフィールドのすべての値を表すことができるunsigned intifに変換unsigned intできます。ビットフィールドがまだ大きい場合、汎整数拡張は適用されません。ビットフィールドに列挙型がある場合、プロモーションの目的でその型の他の値として扱われます。

左のオペランド(ビットフィールド)を昇格すると、が生成されるintため、これがシフト式全体のタイプです。したがって、bあるintプレースホルダ型推論によってすぎ。