在结构和模板中试验联合和位域
Experimenting with Unions and Bitfields within a structures and templates
为了更好地处理和理解位域、联合和结构的字节对齐如何工作,我模拟了一个模板寄存器结构。
我的注册要求如下:
- 寄存器的默认大小或宽度为 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;
};
以上代码在Visual Studio 2017编译器设置为最新草案标准时编译、运行和退出,代码为0。
既然您已经看过代码,我在一定程度上理解了位域和联合,但是当我不经常使用它们时,它们可能会让我有点困惑。我确实知道,当以组合方式使用它们时,它会导致代码不可移植,尤其是在不同的编译器、操作系统和体系结构 (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 符号打印到控制台。
Is it based on a char value type instead of a int type?
char
*是*一个整数类型。该标准允许 std::int8_t
成为 char
.
的类型定义
std::cout << static_cast<std::uint64_t>(r.value.value_) << "\n";
ftw.
为了更好地处理和理解位域、联合和结构的字节对齐如何工作,我模拟了一个模板寄存器结构。
我的注册要求如下:
- 寄存器的默认大小或宽度为 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;
};
以上代码在Visual Studio 2017编译器设置为最新草案标准时编译、运行和退出,代码为0。
既然您已经看过代码,我在一定程度上理解了位域和联合,但是当我不经常使用它们时,它们可能会让我有点困惑。我确实知道,当以组合方式使用它们时,它会导致代码不可移植,尤其是在不同的编译器、操作系统和体系结构 (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 符号打印到控制台。
Is it based on a char value type instead of a int type?
char
*是*一个整数类型。该标准允许 std::int8_t
成为 char
.
std::cout << static_cast<std::uint64_t>(r.value.value_) << "\n";
ftw.