Доступ к std :: uint8_t как std :: bitset - PullRequest
0 голосов
/ 10 сентября 2018

Я хотел бы смоделировать регистр состояния в C / C ++, который должен быть доступен как std :: bitset и как std :: uint8_t .Таким образом, я бы объединил их как объединение следующим образом:

#include <bitset>
#include <iostream>

union byte {
        std::uint8_t uint;
        std::bitset<8> bitset;
};

int main(int, char*[])
{
        byte b = { .uint = 0b10101010 };

        std::cout << "Value of bit 5: "
                << (b.bitset.test(5) ? "true" : "false") << std::endl;

        std::cout << "Value of bit 4: "
                << (b.bitset.test(4) ? "true" : "false") << std::endl;

        std::cout << "Bitset Output: " << b.bitset << std::endl;
        std::cout << "Uint Output: " << static_cast<int>(b.uint) << std::endl;

        return 0;
}

Кажется, это работает как ожидалось, когда скомпилировано с GCC x86_64 8.2 .Однако я хотел бы знать, могу ли я ожидать, что это сработает во всех случаях, или мне лучше с некоторыми вспомогательными функциями, такими как bitset, bittest, ...

Ответы [ 2 ]

0 голосов
/ 10 сентября 2018

Я понял идею комментария SomeProgrammerDude

Что касается вашей проблемы, если вам нужен тип, который может действовать как собственный uint8_t и обрабатывать биты «хорошим» способом, то вам нужно реализовать такой класс самостоятельно. Если вам необходимо сопоставить его с аппаратным регистром, отображаемым в память, вероятно, следует заключить указатель в регистр.

и попытался сделать это на C ++. Вот образец, который я придумал:

#include <cassert>
#include <iostream>
#include <iomanip>

class ByteReg {
  private:
    volatile uint8_t &reg;
  public:
    explicit ByteReg(volatile uint8_t &reg): reg(reg) { }
    ByteReg(const ByteReg&) = delete;
    ByteReg operator=(const ByteReg&) = delete;
    ~ByteReg() = default;

    operator uint8_t() { return reg; }
    bool test(int i) const
    {
      assert(i >= 0 && i < 8);
      return ((reg >> i) & 1) != 0;
    }
};

int main() 
{
  volatile uint8_t hwReg = 0xaa; // 0x10101010
  ByteReg reg(hwReg);
  unsigned value = reg;
  std::cout << "reg: 0x" << std::hex << std::setw(2) << std::setfill('0')
    << value << '\n';
  for (int i = 0; i < 8; ++i) {
    std::cout << "bit " << i << ": "
      << (reg.test(i) ? "set" : "unset") << '\n';
  }
  return 0; 
}

Выход:

reg: 0xaa
bit 0: unset
bit 1: set
bit 2: unset
bit 3: set
bit 4: unset
bit 5: set
bit 6: unset
bit 7: set

Демонстрация в реальном времени на coliru

Тем не менее, автономная функция testBit() может работать с меньшим количеством кода:

#include <cassert>
#include <iostream>
#include <iomanip>

bool testBit(uint8_t reg, int i)
{
  assert(i >= 0 && i < 8);
  return ((reg >> i) & 1) != 0;
}

int main() 
{
  volatile uint8_t reg = 0xaa; // 0x10101010
  unsigned value = reg;
  std::cout << "reg: 0x" << std::hex << std::setw(2) << std::setfill('0')
    << value << '\n';
  for (int i = 0; i < 8; ++i) {
    std::cout << "bit " << i << ": "
      << (testBit(reg, i) ? "set" : "unset") << '\n';
  }
  return 0; 
}

Демонстрация в реальном времени на coliru

0 голосов
/ 10 сентября 2018

То, что вы пытаетесь сделать здесь с помощью union, называется типом наказания и является неопределенным поведением в C ++ (вы можете прочитать больше об этом в этом ответе SO ), поэтому работа не гарантируется должным образом.даже на одном и том же компиляторе.

Более того, даже если это разрешено, std::bitset<8> не гарантирует того же представления, что и std::uint8_t (а на самом деле его нет ни на одном крупном компиляторе).

В вашем случае вы могли бы просто использовать обычный std::bitset<8> с методом to_ulong.

Другая альтернатива - иметь класс-оболочку с элементом bitset, который обеспечивал бы удобные методы для назначения / преобразования вuint8_t.

Кроме того, если вам нужен только ограниченный API, равный std::bitset<8>, было бы неплохо (если вы хотите сохранить размер вашего класса в 1 байт), чтобы обернуть вокруг std::uint8_tи реализовать эти несколько методов (например, test) вручную.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...