вернуть тип доступа к битовому полю - PullRequest
1 голос
/ 23 апреля 2019
#include <iostream>
#include <type_traits>

struct C
{
    uint32_t x : 2;
    bool y : 2;
};

int main()
{
    C c{0b1};

    std::cout << (static_cast<uint32_t>(0b1) << 31) << std::endl;
    std::cout << (c.x << 31) << std::endl;
    std::cout << (c.x << 10) << std::endl;
    std::cout << std::boolalpha << std::is_same_v<decltype(c.x), uint32_t> << std::endl;
    std::cout << std::boolalpha << std::is_same_v<decltype(c.y), bool> << std::endl;
}

Компиляция

g++ -g  test.cpp -std=c++17

g++ (GCC) 8.2.0

выход

2147483648
-2147483648
1024
true
true

Мой вопрос здесь касается типа выражения c.x, где x является 2-битным членом битового поля. Согласно проверке набранных чисел, я получил тот же тип, который был объявлен в определении класса, однако кажется, что это не так во время выполнения, поскольку, когда я пытаюсь установить последний бит посредством сдвига, я получаю отрицательное число. Есть идеи?

1 Ответ

3 голосов
/ 23 апреля 2019

С C ++ черновик 2019-04-12 conv.prom 7.3.6p5 :

7.3.6 Интегральные продвижения

Премия зацелочисленное битовое поле ([class.bit]) может быть преобразовано в значение типа int, если int может представлять все значения битового поля;

Из C ++ черновик2019-04-12 expr.shift 7.6.7p1 :

7.6.7 Операторы сдвига

Операторы сдвига << и >> группируются слева направо.
...
Операнды должны быть целочисленного или незаданного типа перечисления, и выполняются интегральные преобразования.

typeid(c.x) равно uint32_t, однако при использовании оператора << оно неявно преобразуется в int.

c.x равно 0x1.Выражение c.x << 31 равно 0x1 << 31, равно 0x80000000 (при условии sizoef(int) == 4 и CHAR_BIT == 8).Это число интерпретируется как int, а в формате дополняет два оно равно -2147483648 (INT_MIN или что std::intergral_limits<int>::min()).

Обратите внимание, что выражение c.x << 31 в настоящее время (C ++ 17) вызывает неопределенное поведение из-за переполнения целых чисел со знаком.

Кроме того, какое значение имеет тип, объявленный тогда в определении класса?

Перетяжка.Некоторые компиляторы интерпретируют разные типы битовых полей как «разделители-заполнители» (не знаю, как их назвать).Если следующий член в структуре имеет тип, отличный от предыдущего (оба являются битовым полем), то я ожидаю, что компилятор поместит второй член, начиная с нового «свежего» байта.Я ожидал бы, что c.x и c.y будут иметь битовые отступы между ними, поскольку они имеют различный тип.Если это будет struct C { uint32_t y : 2; uint32_t x : 2; }, то компилятор с большей вероятностью поместит их в один и тот же байт.Обратитесь к документации по вашему компилятору или другим ресурсам .

...