根据索引值提取特定字节

Extracting a specific byte based on an index value

本文关键字:字节 提取 索引值      更新时间:2023-10-16

我目前可以从 16 位 int 类型中提取低字节或高字节,并将其存储为 8 位 int 类型。请看下面的代码示例:

#include <bitset>
#include <cassert>
#include <iostream>
#include <vector> // using for std::uint8_t, etc.
// valid values for idx[0,1]
void getByteFrom(std::uint16_t val, std::uint8_t idx, std::uint8_t& res) {  
assert(idx == 0 || idx == 1);
res = ((val >> (idx << 3)) & 0xff);
}
int main() {    
std::uint16_t value = 13579;
std::bitset<16> bits{ value };
std::cout << "Reference Bits:n"
<< bits.to_ulong()
<< 'n' << bits << "nn";
std::uint8_t lowByte = 0, highByte = 0;
getByteFrom(value, 0, lowByte);
getByteFrom(value, 1, highByte);
std::bitset<8> lowBits{ lowByte };
std::bitset<8> highBits{ highByte };
std::cout << "lowByte = " << lowByte << 'n';
std::cout << "lowBits (value): " << lowBits.to_ulong() << 'n';
std::cout << "lowBits (bits):  " << lowBits << "nn";
std::cout << "highByte = " << highByte << 'n';
std::cout << "highBits (value): " << highBits.to_ulong() << 'n';
std::cout << "highBits (bits):  " << highBits << "nn";
return EXIT_SUCCESS;
}

它生成预期和期望的输出。

输出

Reference Bits:
13579
0011010100001011
lowByte = ♂
lowBits (value): 11
lowBits (bits):  00001011
highByte = 5
highBits (value): 53
highBits (bits):  00110101

现在我想做同样的事情,但对于更大的类型......

// u8 = std::uint8_t, u16 = uint16_t, etc.
// valid idx [0,1,2,3]
getByteFrom( u32 val, u8 idx, u8& res );
// valid idx [0,1,2,3,4,5,6,7]
getByteFrom( u64 val, u8 idx, u8& res );
// Also: getting words from dwords and qwords and getting qwords from words
// valid idx[0,1]
getWordFrom( u32 val, u8 idx, u16& res );
// valid idx [0,1,2,3]
getWordFrom( u64 val, u8 idx, u16& res );
// valid idx[0,1]
getDWordFrom( u64 value, u8 idx, u32& res );

知道我可以使用二进制逻辑从单词中获取单个字节:

res = ((val >> (idx << 3)) & 0xff);

我想知道的是,具有位移位和位掩码的二进制逻辑表达式的完整表将是什么作为参考,以便我可以完成编写函数?

注意: -

这是关于以下原始的前两个答案: -

对于用户dhanushka的第一个答案:这可能很有趣,但是上面的函数不是独立的函数,它们将作为一组继承的类构造函数实现。我正在尝试有一个基Register类,并从中创建Reg8Reg16Reg32Reg64类。每个类的基础类型是各自的std::uintx_t,其中x分别为8163264。这些结构将包含该类型的成员作为其数据,以及一个std::bitset<x>,其中x是该类型的位数大小。

构造函数将根据使用的构造函数及其传入的参数设置 uint 类型成员的值。某些构造函数将默认为 0 初始化,其他构造函数将按值或引用(显式)类型传递。如果从较大的尺寸构造以产生较小的尺寸,如果所需的输出不受截断的影响,则可以截断位。然后,构造函数将根据data成员的值初始化bitset<size>成员。

我将使用这些 Register 类作为虚拟机程序中的注册对象。这些类旨在简单,快速但健壮,具有许多功能,成本非常低。为此,我也想尝试对这些类进行模板化,以便大部分开销在编译时完成。

每种类型都代表虚拟CPU的byteworddwordqword大小寄存器。我想包含的一些功能涉及这样一个事实,即您可以轻松快速地反转位的顺序。假设我们有一个u8类型的 Reg8 结构。假设它是由其基础类型的值构造的,假设该值是十进制的 222。由于这是一个std::uint8_t因此在引擎盖下看起来像这样: 十进制二进制十六进制 222 = 1101 1110 0xde

我可以使用bitset'sto_string()函数将其转换为字符串,使用std::reverse反转位的顺序,并使用std::stoi将其转换回int类型并覆盖产生以下内容的原始成员:

dec    binary     hex
123    0111 1011  0x7b

这样,任何将使用此虚拟机库的人都可以以他们需要的任何方式快速调整位的存储。现在在较大大小的寄存器类中,例如 Reg16,其基础类型是std::uint16_t,并且具有具有相同值的伴随std::bitset<16>成员;通过使用位域,人们可以轻松地访问单词中的每个单独字节。我还想合并一个内置函数和模式以在字节序之间切换,这可以即时完成。默认情况下,我想我会坚持使用小端序,因为这就是我的机器。所以不用说,在过去的 4-5 天里,我一直在尝试各种不同的设计模式,试图将所有联轴器放在一起。总的来说,将有4种主要方法来构建这些登记册;默认构造 0 初始化,从底层类型构造并通过传入参数(显式)初始化,从传入参数构造,但依赖于索引值到更大的基类型,最后这些寄存器也应该能够从其他类型的寄存器构造。我可以将 Reg64 传递到 Reg8 构造函数中,并从 8 个字节或 Reg64 中的一个构造一个 Reg8。我还可以从单个 Reg8 构造一个 Reg64,该 Reg8 可以插入到其 8 个字节中的任何一个中,或者从多个 Reg8 中插入。是的,设置这些类有很多复杂性;但这是我所追求的多功能性。

在我的虚拟PC中,这些寄存器将用于模拟真实的寄存器,除了这些是具有双向通信,双向I/O的动态多态寄存器。当然,我以后需要一些标志;我计划使用重载operator<<operator>>的位流过程将这些寄存器最终推送到字符串流中。我可能正在考虑一个基于矢量矩阵的寄存器网络系统,它是虚拟 CPU 的核心部分。

后来当我开始布局我的操作码 - 字节码和助记符时,我认为我不会对它们进行硬编码。我正在考虑拥有一个被读入和解析的属性文件,并且信息将被保存到静态哈希映射中。

因此,当我去构造CPU的操作而不是传统的堆栈类型系统时,该系统的所有操作代码功能都硬编码;这些哈希映射将用于查询适当的操作。这一切也可能随着时间的推移而改变;我正在考虑一个事件驱动的优先级队列类型系统。现在,在一般概念中,CPU中的所有寄存器都将是64位,其中较小的寄存器是通用的。因此,如果我正在创建两种 Reg16 类型并通过操作或字节码进行加法;CPU实际上将采用单个Reg64,并将两个Reg16存储到该64位寄存器的不同字部分中。然后,它将执行提供的两者的相加(可以说是就位),并将结果存储在该寄存器中剩余的字空间之一中。然后,它将移动位,以便获得正确的值。如果您查看了Reg64数据成员的结果,则它可能表示也可能不表示加法的确切值,因为如果结果单词被移动以给出该值,它将取决于指令代码。您还可以轻松查询或返回此值的 Reg16 类型,因为它将被保留。

这是一个小示例,但为简单起见,使用 Reg32 作为基本类型。这可能不准确,但只是为了说明概念而显示。

CPU fetches op codes and gets a set of instructions for 2 Reg8s and to be added and stored into a Reg32. 
// 0x01 - load immediate into reg A
// 0x02 - load immediate into reg B
// 0x10 - add
// 0x0c - store res into 4th byte of Reg32.
// 0xe0 - shift bits in Reg32 to reflect correct value of addition
0000 0001 - load immediate (33) into first byte of Reg32
0000 0010 - load immediate (36) into 2nd byte of Reg32
0001 0000 - add reg & and reg b
0000 1100 - store result of addition into 4th byte of Reg32
1110 0000 - shift bits in Reg32 to reflect actual value of the addition.
// Remember the CPU here is getting a 32bit instruction so all of these 
// byte codes would appear as this in a single 32bit sequence from an 
// instruction register    
// 0x0c100201 this single register contains 4 simultaneous instructions
// This could all possibly be done in one cpu clock cycle, 
// (the relative or conceptual idea, 
// but not necessarily done in practice due to hardware limitations, 
// but can be virtualized) 
// then the next byte code would appear in the 2nd 32 bit register.
// Now imagine this behavior with 64 bit registers. A single 64 bit Register 
// would contain up to 8 byte codes. some byte codes might contain multiple op codes....

如果你在阅读这篇文章时已经做到了这一点,我知道这很长;但我只是想给你尽可能多的详细信息,涵盖我的类设计的所有主要方面,以便你可以更好地了解我正在尝试做什么和实现什么,以及为什么我选择以某种方式尝试做某事。

我很感激你花时间给我一个详细的解释。我将不得不花一些时间来处理这两个提案并测试一些值,看看它是否有助于我在构建课程时获得我正在寻找的正确行为。

我怀疑我是否理解这个问题。但是,如果我这样做,解决方案实际上很容易。

我从OP已经拥有的东西开始:

// valid values for idx[0,1]
void getByteFrom(std::uint16_t val, std::uint8_t idx, std::uint8_t& res) {  
assert(idx == 0 || idx == 1);
res = ((val >> (idx << 3)) & 0xff);
}

我的第一印象是:用idx << 3替换idx * 8是不必要的代码混淆。我敢肯定,任何严肃的现代编译器都可以为以下方面生成相同的高效代码:

// valid values for idx[0,1]
void getByteFrom(std::uint16_t val, std::uint8_t idx, std::uint8_t& res) {  
assert(idx == 0 || idx == 1);
res = ((val >> (idx * 8)) & 0xff);
}

这是getWordFrom()的开始:

// valid idx[0,1]
void getWordFrom(std::uint32_t val, std::uint8_t idx, std::uint16_t& res);

已经提到了对范围[0, 1]idx的必要限制:

void getWordFrom(std::uint32_t val, std::uint8_t idx, std::uint16_t& res)
{ 
assert(idx == 0 || idx == 1);

屏蔽 16 位值的位模式将以二进制0b1111111111111111(具有 16 个 1 位的二进制数)表示。据我所知,C++不支持二进制数文字。相反,十六进制数字文字是首选,因为一个十六进制数字总是准确地反映四个二进制数字,因为 161 =24。(我认为这使得十六进制数在"位移位器"社区中非常受欢迎。因此,屏蔽 16 位值的位模式:0xffff

要将较高的 16 位移动到较低的位置,idx必须乘以 16。

res = ((val >> (idx * 16)) & 0xffff);
}

这并不复杂...(恕我直言)。

请注意,右移(>>)也是为idx == 0完成的,但右移0不会改变该值。

另一种实现可能是:

res = (idx != 0 ? val >> (idx * 16) : val) & 0xffff; // NOT BETTER

只有在idx != 0时才会进行正确的移位.我真的怀疑这是否会赚到什么。我总是更喜欢第一种形式。

(这种微优化通常对整体性能的影响较小或没有影响,实际上不值得考虑。

示例代码:

#include <cstdint>
#include <bitset>
#include <cassert>
#include <iomanip>
#include <iostream>
using U8 = std::uint8_t;
using U16 = std::uint16_t;
using U32 = std::uint32_t;
// valid values for idx[0,1]
void getByteFrom(U16 val, U8 idx, U8 &res)
{  
assert(idx == 0 || idx == 1);
res = ((val >> (idx * 8)) & 0xff);
}
// valid values for idx[0,1]
void getWordFrom(U32 val, U8 idx, U16 &res)
{  
assert(idx == 0 || idx == 1);
res = ((val >> (idx * 16)) & 0xffff);
}
// check this out
int main()
{
{
U16 value = 13579;
std::bitset<16> bits{ value };
std::cout << "Reference Bits:n"
<< bits.to_ulong()
<< 'n' << bits << "nn";
U8 lowByte = 0, highByte = 0;
getByteFrom(value, 0, lowByte);
getByteFrom(value, 1, highByte);
std::bitset<8> lowBits{ lowByte };
std::bitset<8> highBits{ highByte };
std::cout << "lowByte = " << std::setw(2) << std::setfill('0') << std::hex << (unsigned)lowByte << std::dec << 'n';
std::cout << "lowBits (value): " << lowBits.to_ulong() << 'n';
std::cout << "lowBits (bits):  " << lowBits << "nn";
std::cout << "highByte = " << std::setw(2) << std::setfill('0') << std::hex << (unsigned)highByte << std::dec << 'n';
std::cout << "highBits (value): " << highBits.to_ulong() << 'n';
std::cout << "highBits (bits):  " << highBits << "nn";
}
{
U32 value = 135792468;
std::bitset<32> bits{ value };
std::cout << "Reference Bits:n"
<< bits.to_ulong()
<< 'n' << bits << "nn";
U16 lowWord = 0, highWord = 0;
getWordFrom(value, 0, lowWord);
getWordFrom(value, 1, highWord);
std::bitset<16> lowBits{ lowWord };
std::bitset<16> highBits{ highWord };
std::cout << "lowWord = " << std::setw(4) << std::setfill('0') << std::hex << lowWord << std::dec << 'n';
std::cout << "lowBits (value): " << lowBits.to_ulong() << 'n';
std::cout << "lowBits (bits):  " << lowBits << "nn";
std::cout << "highWord = " << std::setw(4) << std::setfill('0') << std::hex << highWord << std::dec << 'n';
std::cout << "highBits (value): " << highBits.to_ulong() << 'n';
std::cout << "highBits (bits):  " << highBits << "nn";
}
}

输出:

Reference Bits:
13579
0011010100001011
lowByte = 0b
lowBits (value): 11
lowBits (bits):  00001011
highByte = 35
highBits (value): 53
highBits (bits):  00110101
Reference Bits:
135792468
00001000000110000000011101010100
lowWord = 0754
lowBits (value): 1876
lowBits (bits):  0000011101010100
highWord = 0818
highBits (value): 2072
highBits (bits):  0000100000011000

科里鲁的现场演示

您也可以使用模板来完成。这是代码:

#include <cstdint>
#include <cassert>
#include <type_traits>
template <typename T, typename U>
void getValAtIdx(T val, uint8_t idx, U& res) {
assert(std::is_integral<T>::value && std::is_integral<U>::value);
assert((sizeof(val) > sizeof(res)) && (sizeof(val)/sizeof(res) > idx));
res = (val >> ((sizeof(res) << 3)*idx)) & ((T)-1 >> ((sizeof(val)-sizeof(res)) << 3));
}

我没有做彻底的测试,但我认为逻辑是可以的。

以下应导致断言失败

uint16_t res;
uint64_t val = 0x12345678;
getValAtIdx<uint64_t, uint16_t>(val, 4, res);

uint16_t res;
uint64_t val = 0x12345678;
getValAtIdx<uint64_t, uint16_t>(val, 1, res);

应该给你0x1234。

坐在那里一点一点地手工做一些数学运算以识别模式之后,我能够在一些函数模板的帮助下真正简化我的代码。这是我到目前为止所拥有的,这些值似乎与我的期望相匹配。


编辑:

我在common.h中添加了一些 typedef,并将我的函数模板移到其中以简化代码的可读性。我删除了幻数并用常量替换了它们,我可能也调整了一些条件检查。我什至将我的代码包装在一个命名空间中。我还将包括我预期的注册类,因为它们即将完成,但不会在此主要中使用它们.cpp-*


编辑

我找到了更多能够替换我的 typedef 的位置。更重要的是,我在注册类中发现了一个错误,当 我正在对它们进行单元测试。该错误与声明type valuebitset<T>的顺序有关。最初,我首先bitset<T>声明,因此这是初始化的第一件事。我不得不切换声明的顺序,现在到目前为止一切似乎都很好。所有基本构造函数都已完成。现在,需要编写将从多个较小的寄存器类型创建寄存器类型的构造函数:示例...Reg32( Reg8, Reg8, Reg16 ); 最后 构造函数集将采用较小的 uint 类型或较小的 Reg 类型以及索引值,例如:Reg64( Reg32, 0 );这会将 Reg32 中的位分配到 Reg64 和 Reg32 的低 DWord( Reg8 3, Reg8 0 );这会将第一个 Reg8 的位序列分配到 Reg32 的高字节中,将第二个位序列分配给 Reg32 的低字节,中间的所有位将保持与之前的值不变。

-

更新的代码-

主.cpp

#include "common.h"
//#include "Register.h" // if you include this you don't need to include common.h
int main() {
using namespace nesx;
std::uint16_t v16 = 23990;
std::cout << "Byte Testing v16 = 23990n";
testBytes(v16);
std::uint32_t v32 = 1801285115;
std::cout << "Byte Testing v32 = 1801285115n";
testBytes(v32);
std::cout << "Word Testing v32 = 1801285115n";
testWords(v32);
std::uint64_t v64 = 7486836904524374950;
std::cout << "Byte Testing v64 = 7486836904524374950n";
testBytes(v64);
std::cout << "Word Testing v64 = 7486836904524374950n";
testWords(v64); 
std::cout << "DWord Testing v64 = 7486836904524374950n";
testDWords(v64);
return EXIT_SUCCESS;
}

普通.h

#pragma once
#include <algorithm>
#include <bitset>
#include <cassert>
#include <cstdint>
#include <iostream>
#include <memory>
#include <map>
#include <string>
#include <sstream>
#include <vector>
namespace nesx {
typedef std::int8_t i8;
typedef std::int16_t i16;
typedef std::int32_t i32;
typedef std::int64_t i64;
typedef std::uint8_t u8;
typedef std::uint16_t u16;
typedef std::uint32_t u32;
typedef std::uint64_t u64;
const u16 BYTE = 0x08, WORD = 0x10, DWORD = 0x20, QWORD = 0x40;
typedef std::bitset<BYTE>  Byte;
typedef std::bitset<WORD>  Word;
typedef std::bitset<DWORD> DWord;
typedef std::bitset<QWORD> QWord;
template<typename T>
void getByteFrom(T val, u8 idx, u8& res) {
res = ((val >> (idx * 8) & 0xff));
}
template<typename T>
void getWordFrom(T val, u8 idx, u16& res) {
res = ((val >> (idx * 16) & 0xffff));
}
template<typename T>
void getDWordFrom(T val, u8 idx, u32& res) {
res = ((val >> (idx * 32) & 0xffffffff));
}
// Direct Byte Alignment No Offsets
template<typename T>
void testBytes(T& value) {
const u16 size = sizeof(T);
const u16 numBits = size * BYTE;
// Make sure that T is either a word, dword or qword
if (numBits < WORD) {
return;
}
if (numBits == WORD) {
Word wordBits{ value };
std::cout << "Reference Bits:n"
<< "value = " << wordBits.to_ullong() << 'n'
<< "bits  = " << wordBits << "nn";
}
if (numBits == DWORD) {
DWord dwordBits{ value };
std::cout << "Reference Bits:n"
<< "value = " << dwordBits.to_ullong() << 'n'
<< "bits  = " << dwordBits << "nn";
}
if (numBits == QWORD) {
QWord qwordBits{ value };
std::cout << "Reference Bits:n"
<< "value = " << qwordBits.to_ullong() << 'n'
<< "bits  = " << qwordBits << "nn";
}
std::vector<u8> bytes;
std::vector<Byte> byteBits;
bytes.resize(size, 0);
byteBits.resize(size, 0);
// Populate Our Vectors with Data
for (u8 idx = 0; idx < size; idx++) {
8 byte = 0;
getByteFrom(value, idx, byte);
bytes[idx] = byte;Byte bits{ byte };
byteBits[idx] = bits;
}
// Now loop through and print out the information
// from the vectors
for (std::size_t i = 0; i < size; i++) {
std::cout << "byte[" << i << "] = " << +bytes[i] << 'n';
std::cout << "bitset (value): " << byteBits[i].to_ullong() << 'n';
std::cout << "bitset  (bits): " << byteBits[i] << "nn";
}
}
// Direct Word Alignment No Offsets
template<typename T>
void testWords(T& value) {
const u16 size = sizeof(T);
const u16 numBits = size * BYTE;
// Make sure T is either a dword or a qword
if (numBits < DWORD) {
return;
}
if (numBits == DWORD) {
DWord dwordBits{ value };
std::cout << "Reference Bits:n"
<< "value = " << dwordBits.to_ullong() << 'n'
<< "bits  = " << dwordBits << "nn";}
if (numBits == QWORD) {
QWord qwordBits{ value };
std::cout << "Reference Bits:n"
<< "value = " << qwordBits.to_ullong() << 'n'
<< "bits  = " << qwordBits << "nn";
}
const u16 numWords = size / 2;
std::vector<u16> words;
std::vector<Word> wordBits;
words.resize(numWords, 0);
wordBits.resize(numWords, 0);
// Populate Our Vectors with Data
for (u8 idx = 0; idx < numWords; idx++) {
u16 word = 0;
getWordFrom(value, idx, word);
words[idx] = word;
Word bits{ word };
wordBits[idx] = bits;
}
// Now loop through and print out the information
// from the vectors
for (std::size_t i = 0; i < numWords; i++) {
std::cout << "word[" << i << "] = " << words[i] << 'n';
<< "bitset (value): " << wordBits[i].to_ullong(
<< 'n';
std::cout << "bitset  (bits): " << wordBits[i] << "nn";
}
}
// Direct DWord Alignment No Offsets
template<typename T>
void testDWords(T& value) {
const u16 size = sizeof(T);
const u16 numBits = size * BYTE;
// Make sure T is a qword
if (numBits < QWORD) {
return;
}
if (numBits == QWORD) {
QWord qwordBits{ value };
std::cout << "Reference Bits:n"
<< "value = " << qwordBits.to_ullong() << 'n'
<< "bits  = " << qwordBits << "nn";
}
const u16 numDWords = size / 4;
std::vector<u32> dwords;
std::vector<DWord> dwordBits;
dwords.resize(numDWords, 0);
dwordBits.resize(numDWords, 0);
// Populate Our Vectors with Data
for (u8 idx = 0; idx < numDWords; idx++) {
u32 dword = 0;
getDWordFrom(value, idx, dword);
dwords[idx] = dword;
DWord bits{ dword };
dwordBits[idx] = bits;
}
// Now loop through and print out the information from the vectors
for (std::size_t i = 0; i < numDWords; i++) {
std::cout << "dword[" << i << "] = " << dwords[i] << 'n';
std::cout << "bitset (value): " << dwordBits[i].to_ullong() << 'n';
std::cout << "bitset  (bits): " << dwordBits[i] << "nn";
}
}
} // namespace nesx

注册.h

#pragma once
#include "common.h"
namespace nesx {
template<typename T>
struct Register {
T data;
Register() = default;
};
struct Reg8 : public Register<u8> {
u8 value;  // must be declared before std::bitset<T>
Byte bits; // otherwise you will not get the proper bit sequence
// Default 0 Initialized Constructor
Reg8() : value{ 0 }, bits{ value } { this->data = 0; }
// Constructors by Register Sized Values
// Constructor of smaller types that takes larger types,
// has to be casted by a narrowing convention
explicit Reg8(u8& val)  : value{ val }, bits{ value } {
this->data = value;
}
explicit Reg8(u16& val) : value{ static_cast<u8>(val) }, bits{ value } {
this->data = value;
}
explicit Reg8(u32& val) : value{ static_cast<u8>(val) }, bits{ value } {
this->data = value;
}
explicit Reg8(u64& val) : value{ static_cast<u8>(val) }, bits{ value } {
this->data = value;
}
Reg8(u16 val, u8 idx ) {
assert( idx == 0 || idx == 1 );
getByteFrom(val, idx, this->value);
bits = value;
this->data = value;
}
Reg8(u32 val, u8 idx) {
assert(idx <= 0 && idx >= 3);
getByteFrom(val, idx, this->value);
bits = value;
this->data = value;
}
Reg8(u64 val, u8 idx) {
assert(idx <= 0 && idx >= 7);
getByteFrom(val, idx, this->value);
bits = value;
this->data = value;
}
// Constructors by Register Types
template<typename T>
explicit Reg8(Register<T>* reg) {
this->value = static_cast<u8>( reg->data );
this->bits = value;
}
template<typename T>
Reg8(Register<T>* reg, u8 idx) {
// first we need to know what type T is to determine 
// how many bytes are in T so that we can assert our
// index properly for each different type
u16 size = sizeof(T); // in bytes
if (size == BYTE)  { /* TODO: */ }
if (size == WORD)  { /* TODO: */ }
if (size == DWORD) { /* TODO: */ }
if (size == QWORD) { /* TODO: */ }
}
};
struct Reg16 : public Register<u16> {
u16 value;  // Must be declared before std::bitset<t>
Word bits;  // otherwise you will not get the proper bit sequence
// Default 0 Initialized Constructor
Reg16() : value{ 0 }, bits{ value } { this->data = 0; }
// Constructors by Register Sized Values
// Constructor of smaller types that takes larger types,
// has to be casted by a narrowing convention
explicit Reg16(u16& val) : value{ val }, bits{ value } {
this->data = value;
}
explicit Reg16( u8& val) : value{ val }, bits{ value } {
this->data = value;
}
explicit Reg16(u32& val) : value{ static_cast<u16>(val) }, bits{ value } {
this->data = value;
}
explicit Reg16(u64& val) : value{ static_cast<u16>(val) }, bits{ value } {
this->data = value;
}
// TODO:
// low is right side, high is left side of the bitset...
// Reg16( u8& byte0, u8& byte1 ) { ... } // byte0 = low && byte1 = high
Reg16( u32 val, u8  idx) {
assert(idx == 0 || idx == 1);
getWordFrom(val, idx, this->value);
bits = value;
this->data = value;
}
Reg16(u64 val, u8 idx) {
assert(idx <= 0 || idx <= 3);
getWordFrom(val, idx, this->value);
bits = value;
this->data = value;
}
// Constructors by Register Types
template<typename T>
explicit Reg16(Register<T>* reg) {
this->value = static_cast<u16>(reg->data);
this->bits = value;
}
};
struct Reg32 : public Register<u32> {
u32 value;  // must be declared before std::bitset<T>
DWord bits; // otherwise you will not get the proper bit sequence
// Default 0 Initialized Constructor
Reg32() : value{ 0 }, bits{ value } { this->data = 0; }
// Constructors by Register Sized Values
// Constructor of smaller types that takes larger types,
// has to be casted by a narrowing convention
explicit Reg32(u32& val) : value{ val }, bits{ value } {
this->data = value;
}
explicit Reg32( u8& val) : value{val}, bits{value} {
this->data = value;
}
explicit Reg32(u16& val) : value{val}, bits{value} {
this->data = value;
}
explicit Reg32(u64& val) : value{ static_cast<u32>(val) }, bits{ value } {
this->data = value;
}
// TODO: 
// low is right side, high is left side of bitset
// Reg32( u8 byte0, u8 byte1, u8 byte2, u8 byte3 ) { ... } // byte0 = low ... byte3 = high
// Reg32( u16 word0, word1 ) { ... } // word0 = low  word1 = high
Reg32(u64 val, u8 idx) {
assert(idx == 0 || idx == 1);
getDWordFrom(val, idx, this->value);
bits = value;
this->data = value;
}
// Constructors by Register Types
template<typename T>
explicit Reg32(Register<T>* reg) {
this->value = static_cast<u32>(reg->data);
this->bits = value;
}
};
struct Reg64 : public Register<u64> {
u64 value;  // Must be declared before std::bitset<T>
QWord bits; // Otherwise you will not get the proper bit sequence
// Default 0 Initialized Constructor
Reg64() : value{ 0 }, bits{ value } { this->data = 0; }
// Constructors by Register Sized Values
// Constructor of smaller types that takes larger types,
// has to be casted by a narrowing convention
explicit Reg64(u64& val) : value{ val }, bits{ value }{
this->data = value;
}
explicit Reg64( u8& val) : value{ static_cast<u64>(val) }, bits{ value } {
this->data = value;
}
explicit Reg64(u16& val) : value{ static_cast<u64>(val) }, bits{ value } {
this->data = value;
}
explicit Reg64(u32& val) : value{ static_cast<u64>(val) }, bits{ value } {
this->data = value;
}
// TODO:
// low is right side, high is left side of bitset
// Reg64( u8 b0, u8 b1, u8 b2, u8 b3, u8 b4, u8 b5, u8 b6, u8 b7 ) {...} b0 = low ... b7 = high
// Reg64( u16 w0, u16 w1, u16 w2, u16, w3 );
// Reg64( u32 dw0, u32 dw1 );
// Constructors by Register Types
template<typename T>
explicit Reg64(Register<T>* reg) {
this->value = static_cast<u64>(reg->data);
this->bits = value;
}
};
};

这里唯一的区别是我不asserting这些模板函数,但是当我将此代码移植到我的类或结构的构造函数中时,我将在那里断言适当的值。


这是输出:

Byte Testing v16 = 23990
Reference Bits:
value = 23990
bits  = 0101110110110110
byte[0] = ╢     // with promoted uchar 182
bitset (value): 182
bitset  (bits): 10110110
byte[1] = ]     // with promoted uchar 93
bitset (value): 93
bitset  (bits): 01011101
Byte Testing v32 = 1801285115
Reference Bits:
value = 1801285115
bits  = 01101011010111010110110111111011
byte[0] = √     // with promoted uchar 251
bitset (value): 251
bitset  (bits): 11111011
byte[1] = m     // with promoted uchar 109
bitset (value): 109
bitset  (bits): 01101101
byte[2] = ]     // with promoted uchar 93
bitset (value): 93
bitset  (bits): 01011101
byte[3] = k     // with promoted uchar 107
bitset (value): 107
bitset  (bits): 01101011
Word Testing v32 = 1801285115
Reference Bits:
value = 1801285115
bits  = 01101011010111010110110111111011
word[0] = 28155
bitset (value): 28155
bitset  (bits): 0110110111111011
word[1] = 27485
bitset (value): 27485
bitset  (bits): 0110101101011101
Byte Testing v64 = 7486836904524374950
Reference Bits:
value = 7486836904524374950
bits  = 0110011111100110100101100111111101101001011101011110001110100110
byte[0] = ª     // with promoted uchar 166
bitset (value): 166
bitset  (bits): 10100110
byte[1] = π     // with promoted uchar 227
bitset (value): 227
bitset  (bits): 11100011
byte[2] = u     // with promoted uchar 117
bitset (value): 117
bitset  (bits): 01110101
byte[3] = I     // with promoted uchar 105
bitset (value): 105
bitset  (bits): 01101001
byte[4] = ⌂     // with promoted uchar 127
bitset (value): 127
bitset  (bits): 01111111
byte[5] = û     // with promoted uchar 150
bitset (value): 150
bitset  (bits): 10010110
byte[6] = µ     // with promoted uchar 230
bitset (value): 230
bitset  (bits): 11100110
byte[7] = g     // with promoted uchar 103
bitset (value): 103
bitset  (bits): 01100111
Word Testing v64 = 7486836904524374950
Reference Bits:
value = 7486836904524374950
bits  = 0110011111100110100101100111111101101001011101011110001110100110
word[0] = 58278
bitset (value): 58278
bitset  (bits): 1110001110100110
word[1] = 26997
bitset (value): 26997
bitset  (bits): 0110100101110101
word[2] = 38527
bitset (value): 38527
bitset  (bits): 1001011001111111
word[3] = 26598
bitset (value): 26598
bitset  (bits): 0110011111100110
DWord Testing v64 = 7486836904524374950
Reference Bits:
value = 7486836904524374950
bits  = 0110011111100110100101100111111101101001011101011110001110100110
dword[0] = 1769333670
bitset (value): 1769333670
bitset  (bits): 01101001011101011110001110100110
dword[1] = 1743165055
bitset (value): 1743165055
bitset  (bits): 01100111111001101001011001111111

让我知道你的想法!


用更新的版本替换我的代码后,这里有一些关于我的寄存器类的信息,你可以从任何uint类型构造任何寄存器类型:Reg8,Reg16,Reg32和Reg64:u8,u16,u32和u64通过直接值。您还可以通过其他寄存器类型的指针或地址来构造它们。您也可以有选择地构造它们。我的意思是你可以将 Reg16 声明为类型变量。您可以将 u64 和值 2 作为索引值传递给它。这种构造函数将从右侧获取 3 个单词,并使用它来构造 Reg16 类型。这种行为可以从任何较大的类型到较小的类型。给我更多时间,我将在这些寄存器类型中包含更多功能。我想在这里得到您的反馈!