Чтобы лучше понять и понять, как работают битовые поля, объединения и байтовое выравнивание структур, я моделирую структуру регистра шаблона.
Требования моего регистра следующие:
- Размер или ширина регистра по умолчанию - 8 бит или 1 байт
- Регистры большего размера должны быть кратны 8
- Регистры меньше или равны 64 битамили 8 байтов.
У меня есть набор структур, которые строятся друг от друга в каскадном эффекте, начиная с базовой единицы байта и заканчивая QWord.
Мои регистрыявляются шаблонными специализациями.
Вот мой код:
-main.cpp-
#include <iostream>
#include "Register.h"
int main() {
Register r1;
r1.value.value_ = 8;
Register<16> r2;
r2.value.value_ = 16;
Register<32> r3;
r3.value.value_ = 32;
Register<64> r4;
r4.value.value_ = 64;
std::cout << static_cast<std::uint8_t>( r1.value.value_) << "\n";
std::cout << static_cast<std::uint16_t>(r2.value.value_) << "\n";
std::cout << static_cast<std::uint32_t>(r3.value.value_) << "\n";
std::cout << static_cast<std::uint64_t>(r4.value.value_) << "\n";
return EXIT_SUCCESS;
}
-Register.h-
#pragma once
#include <vector> // include for typedefs below.
typedef std::int8_t i8;
typedef std::int16_t i16;
typedef std::int32_t i32;
typedef std::int64_t i64;
struct MyByte {
union {
i8 value_;
struct {
i8 b0 : 1;
i8 b1 : 1;
i8 b2 : 1;
i8 b3 : 1;
i8 b4 : 1;
i8 b5 : 1;
i8 b6 : 1;
i8 b7 : 1;
};
};
};
struct MyWord { // same as short or i16
union {
i16 value_;
union {
MyByte byte_[2];
struct {
MyByte b0_;
MyByte b1_;
};
};
};
};
struct MyDWord { // same as int or i32
union {
i32 value_;
struct {
MyWord w0_;
MyWord w1_;
};
union {
MyByte byte_[4];
struct {
MyByte b0_;
MyByte b1_;
MyByte b2_;
MyByte b3_;
};
};
};
};
struct MyQWord { // same as long or i64
union {
i64 value_;
struct {
MyDWord d0_;
MyDWord d1_;
};
struct {
MyWord w0_;
MyWord w1_;
MyWord w2_;
MyWord w3_;
};
union {
MyByte byte_[8];
struct {
MyByte b0_;
MyByte b1_;
MyByte b2_;
MyByte b3_;
MyByte b4_;
MyByte b5_;
MyByte b6_;
MyByte b7_;
};
};
};
};
template<size_t N = 8>
struct Register {
MyByte value;
Register() {
static_assert(
((N % 8) == 0) &&
(N >= 8) &&
(N <= 64)
);
}
};
template<>
struct Register<16> {
MyWord value;
Register() = default;
};
template<>
struct Register<32> {
MyDWord value;
Register() = default;
};
template<>
struct Register<64> {
MyQWord value;
Register() = default;
};
Приведенный выше код компилируется, запускается и завершается с кодом 0 в Visual Studio 2017 с компилятором, настроенным на последний набросок стандарта.
Теперь, когда у вас естьвидел код, я понимаю битовые поля и союзы в некоторой степени, но чтоProjectSyndicate ru Я не использую их все так часто, что они могут немного меня поднять.Я знаю, что при их использовании, особенно в сочетании, это может привести к тому, что код не будет переносимым, особенно между различными компиляторами, операционными системами и архитектурами (endian).
Однако это всего лишь экспериментальный код, на котором можно попрактиковатьсяони как хороший переподготовка.
Проблема, с которой я столкнулся, заключается в моей работе.Все регистры более высокого порядка, кажется, работают нормально, я только протестировал получение его непосредственно через внутреннюю переменную-член value_ напрямую.Тем не менее, я получаю результаты из стандартного или самого основного регистра 8-битного размера.Со значениями, установленными как они есть в настоящее время.Я получаю это как вывод:
--
16
32
64
И если я изменю свой основной на это:
#include <iostream>
#include "Register.h"
int main() {
Register r;
for (i8 i = 0; i < 21; i++) {
1.value.value_ = i;
std::cout << static_cast<std::uint8_t>(r.value.value_) << "\n";
}
return EXIT_SUCCESS;
}
Я получаю этот вывод с звуковым сигналом, где-то в миксе его:
☺
☻
♥
♦
♣
♠
♂
♀
♫
☼
►
◄
↕
‼
¶
Это как-то связано с тем, как определяется std::int8_t
?Он основан на типе значения char
вместо типа int
?Это все еще должно быть целым, хотя ... если это так, то каким образом он должен иметь дело со значениями без знака в объединениях или битовых полях и т. Д.?Что приводит к выводу символов ASCII на консоль.