unsigned int of bit-field가 C ++에서 shift 연산 후 signed int가되는 이유는 무엇입니까? [복제]

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입니다 int하지만 uint32_t.

나는 그것을 발견, uint16_t그리고 uint8_t또한 시프트 연산자 후 서명 INT 될 것이며, 비슷한 질문이 있었다 C#피연산자가 <32 비트 때 결과가 체결 될 것이라는 결론에 도달했다. 피연산자가 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 int경우 로 변환 될 수 있습니다 unsigned int. 비트 필드가 아직 더 크면 적분 승격이 적용되지 않습니다. 비트 필드에 열거 된 유형이있는 경우 승격 목적으로 해당 유형의 다른 값으로 처리됩니다.

왼쪽 피연산자 (비트 필드)의 승격은를 생성 int하므로 이것이 전체 시프트 표현식의 유형입니다. 따라서 b입니다 int너무 자리 표시 자 형태 추론에 의해.