根据索引值提取特定的字节

时间:2019-05-11 06:02:20

标签: c++ bit-manipulation byte c++17

我目前可以从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 << "\n\n";

    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 << "\n\n";

    std::cout << "highByte = " << highByte << '\n';
    std::cout << "highBits (value): " << highBits.to_ulong() << '\n';
    std::cout << "highBits (bits):  " << highBits << "\n\n";

    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初始化,另一些构造函数将通过值或引用(显式)类型传递。如果从所需的输出不受截断的影响,从较大的大小构造以产生较小的大小,则可以截断位。然后,构造函数将根据bitset<size>成员的值初始化data成员。

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

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

我可以使用bitset's to_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(可以插入其8个字节中的任意一个)或从多个Reg8中构造Reg64。是的,设置这些类非常复杂。但它是我追求的多功能性。

在我的虚拟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....

如果您在阅读本文时走了这么远,我知道这很长。但我只是想为您提供尽可能详尽的信息,涵盖我班级设计的所有主要方面,以便您可以更好地了解我正在努力实现的目标以及为什么这样做。我选择尝试以某种方式做某事。

我很感谢您花时间给我答复并提供一些详细的说明。我将花一些时间处理这两个建议并测试一些值,以查看它是否有助于我在构建类时寻求正确的行为。

3 个答案:

答案 0 :(得分:1)

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

我从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 * 8替换idx << 3是不必要的代码混淆。我敢肯定,任何严肃的现代编译器都可以为以下对象产生相同的有效代码:

// 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);

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

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

用于掩盖16位值的位模式将采用二进制0b1111111111111111(具有16个1位数字的二进制数)。我知道在C ++中不支持二进制数字文字。取而代之的是,最好使用十六进制数字,因为一个十六进制数字总是总是恰好代表四个二进制数字,因为16 1 = 2 4 。 (我认为这使得十六进制数字在“移位器”社区中非常受欢迎。)因此,该掩码掩盖了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 << "\n\n";

    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 << "\n\n";

    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 << "\n\n";
  }
  {
    U32 value = 135792468;
    std::bitset<32> bits{ value };
    std::cout << "Reference Bits:\n"
              << bits.to_ulong()
              << '\n' << bits << "\n\n";

    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 << "\n\n";

    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 << "\n\n";
  }
}

输出:

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

Live Demo on coliru

答案 1 :(得分:1)

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

#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。

答案 2 :(得分:1)

坐在那里并一点一点地手工进行一些数学运算以识别模式之后,我能够借助一些功能模板来真正简化我的代码。这是我到目前为止的内容,这些值似乎与我的期望相符。


编辑:

  

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

中使用它们。

修改

  

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


-更新的代码-

main.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 = 23990\n";
    testBytes(v16);

    std::uint32_t v32 = 1801285115;
    std::cout << "Byte Testing v32 = 1801285115\n";
    testBytes(v32);
    std::cout << "Word Testing v32 = 1801285115\n";
    testWords(v32);

    std::uint64_t v64 = 7486836904524374950;
    std::cout << "Byte Testing v64 = 7486836904524374950\n";
    testBytes(v64);
    std::cout << "Word Testing v64 = 7486836904524374950\n";
    testWords(v64); 
    std::cout << "DWord Testing v64 = 7486836904524374950\n";
    testDWords(v64);

    return EXIT_SUCCESS;
}

common.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 << "\n\n";
        }
        if (numBits == DWORD) {
            DWord dwordBits{ value };
            std::cout << "Reference Bits:\n"
                      << "value = " << dwordBits.to_ullong() << '\n'
                      << "bits  = " << dwordBits << "\n\n";
        }
        if (numBits == QWORD) {
            QWord qwordBits{ value };
            std::cout << "Reference Bits:\n"
                      << "value = " << qwordBits.to_ullong() << '\n'
                      << "bits  = " << qwordBits << "\n\n";
        }

        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] << "\n\n";
        }
    }

    // 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 << "\n\n";}

        if (numBits == QWORD) {
            QWord qwordBits{ value };
            std::cout << "Reference Bits:\n"
                      << "value = " << qwordBits.to_ullong() << '\n'
                      << "bits  = " << qwordBits << "\n\n";
        }

        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] << "\n\n";
        }
    }

    // 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 << "\n\n";
        }

        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] << "\n\n";
        }
    }
} // 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

让我知道您的想法!


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