Заполнение структуры объединением членов std :: bitset - PullRequest
0 голосов
/ 07 мая 2019

После того, как я решил свою проблему до этого вопроса Я продолжил расширять эту версию своего кода, чтобы включить объединения полей данных из моих предыдущих версий шаблона с этой версией, и у меня это пока :

main.cpp

#include <iostream>
#include <type_traits>
#include "Register.h"

int main() {
    using namespace vpc;

    std::cout << std::boolalpha;

    std::cout << "std::bitset<64> is trivially copyable "
        << std::is_trivially_copyable<std::bitset<64>>::value << '\n'
        << "QWord is trivially copyable "
        << std::is_trivially_copyable<QWord>::value << '\n'
        << "DWord is trivially copyable "
        << std::is_trivially_copyable<DWord>::value << '\n'
        << "Word is trivially copyable "
        << std::is_trivially_copyable<Word>::value << '\n'
        << "Byte is trivially copyable "
        << std::is_trivially_copyable<Byte>::value << '\n'
        //      << "Bits is trivially copyable "
        //<< std::is_trivially_copyable<Bits>::value << '\n'
        << "My Register is trivially copyable "
        << std::is_trivially_copyable<Register>::value << "\n\n";


    std::cout << "sizeof(std::bitset<Byte>) = "  << sizeof(Byte)  << " bytes\n";
    std::cout << "sizeof(std::bitset<Word>) = "  << sizeof(Word)  << " bytes\n";
    std::cout << "sizeof(std::bitset<DWord>) = " << sizeof(DWord) << " bytes\n";
    std::cout << "sizeof(std::bitset<QWord>) = " << sizeof(QWord) << " bytes\n";
    std::cout << "sizeof(Register) = "      << sizeof(Register) << " bytes\n\n";

    Register r;

    std::cout << "sizeof(Register::byte) = " << sizeof(r.byte)  << " bytes\n";
    std::cout << "sizeof(Register::Byte) = " << sizeof(r.byte) / sizeof(r.byte[0]) << " bytes\n";

    std::cout << "sizeof(Register::word) = " << sizeof(r.word)  << " bytes\n";
    std::cout << "sizeof(Register::Word) = " << sizeof(r.word) / sizeof(r.word[0]) << " bytes\n";

    std::cout << "sizeof(Register::dword) = " << sizeof(r.dword) << " bytes\n";
    std::cout << "sizeof(Register::DWord) = " << sizeof(r.dword) / sizeof(r.dword[0]) << " bytes\n";

    std::cout << "sizeof(Register::value) = " << sizeof(r.value) << " bytes\n";

    std::cout << "sizeof(Register) = " << sizeof(r) << " bytes\n\n";

    r.value = 0xFFFFFFFFFFFFFFFF;
    std::cout << "value = " << r.value.to_ullong() << '\n' << r.value << '\n';
    for (std::uint16_t i = 0; i < 8; i++) {
        std::cout << "byte_" << i << " : " << r.byte[i] << '\n';
    }

    return EXIT_SUCCESS;
}

Register.h

#pragma once

#include <algorithm>
#include <bitset>
#include <string>
#include <vector> // include for typedefs below.

namespace vpc {
    typedef std::int8_t  i8;
    typedef std::int16_t i16;
    typedef std::int32_t i32;
    typedef std::int64_t i64;

    const std::uint16_t BYTE = 0x08;
    const std::uint16_t WORD = 0x10;
    const std::uint16_t DWORD = 0x20;
    const std::uint16_t QWORD = 0x40;

    typedef std::bitset<BYTE>  Byte;
    typedef std::bitset<WORD>  Word;
    typedef std::bitset<DWORD> DWord;
    typedef std::bitset<QWORD> QWord;

    struct Register {

        union {
            QWord value{ 0 };

            union {
                DWord dword[2];
                struct {
                    DWord dword0;
                    DWord dword1;
                };
            };

            union {
                Word word[4];
                struct {
                    Word word0;
                    Word word1;
                    Word word2;
                    Word word3;
                };
            };

            union {
                Byte byte[8];
                struct {
                    Byte byte0;
                    Byte byte1;
                    Byte byte2;
                    Byte byte3;
                    Byte byte4;
                    Byte byte5;
                    Byte byte6;
                    Byte byte7;
                };
            };
        };

        Register() : value{ 0 } {}
    };

    Register reverseBitOrder(Register& reg, bool copy = false);

} // namespace vpc

Register.cpp

#include "Register.h"

namespace vpc {

    Register reverseBitOrder(Register& reg, bool copy) {
        auto str = reg.value.to_string();
        std::reverse(str.begin(), str.end());

        if (copy) { // return a copy
            Register cpy;
            cpy.value = QWord(str);
            return cpy;
        }
        else {
            reg.value = QWord(str);
            return {};
        }
    }

} // namespace vpc

выход

std::bitset<64> is trivially copyable true
QWord is trivially copyable true
DWord is trivially copyable true
Word is trivially copyable true
Byte is trivially copyable true
My Register is trivially copyable true

sizeof(std::bitset<Byte>) = 4 bytes
sizeof(std::bitset<Word>) = 4 bytes
sizeof(std::bitset<DWord>) = 4 bytes
sizeof(std::bitset<QWord>) = 8 bytes
sizeof(Register) = 32 bytes

sizeof(Register::byte) = 16 bytes
sizeof(Register::Byte) = 4 bytes
sizeof(Register::word) = 16 bytes
sizeof(Register::Word) = 4 bytes
sizeof(Register::dword) = 8 bytes
sizeof(Register::DWord) = 2 bytes
sizeof(Register::value) = 8 bytes
sizeof(Register) = 32 bytes

value = 18446744073709551615
1111111111111111111111111111111111111111111111111111111111111111
byte_0 : 11111111
byte_1 : 11111111
byte_2 : 11001100
byte_3 : 11001100
byte_4 : 11001100
byte_5 : 11001100
byte_6 : 11001100
byte_7 : 11001100

После просмотра распечатанных данных о размерах типов bitset и сравнения их с фактическими размерами в качестве членов структуры внутри объединения. Я пытаюсь выяснить, что здесь происходит под капотом.

Я не уверен, правильно ли я выполняю вычисления sizeof, если это связано с внутренним хранилищем bitset Я пытаюсь понять выравнивание данных в контексте союзов как членов структуры, в которой базовым типом является тип std::bitset типов. Из заголовка видно, что существует 4 варианта: bitset<8> = Byte, bitset<16> = Word, bitset<32> = DWord & bitset<64> = QWord

В сущностях должно быть делимое отображение этих:

// each [] = 1 byte or 8 bits for simplicity
bitset<64> = [] [] [] [] [] [] [] []
bitset<32> = [] [] [] []
bitset<16> = [] []
bitset<8>  = []

Поэтому, когда я пытаюсь использовать их в союзе как таковой:

union {
    QWord q;

    union {
        DWord d[2];
        struct {
            DWord d_0;
            DWord d_1;
        };
    };

    union {
        Word w[4];
        struct {
            Word w_0;
            Word w_1;
            Word w_2;
            Word w_3;
         };
    };

    union {
        Byte b[8];
        struct {
            Byte b_0;
            Byte b_1;
            Byte b_2;
            Byte b_3;
            Byte b_4;
            Byte b_5;
            Byte b_6;
            Byte b_7; 
        };
    };
};

Я бы подумал, что, используя шаблон, который я показал над этим объединением, я смогу упаковать данные в выравнивание размера байта:

// each inner [] = 1 byte or 8 bits
// and each outer [] = index into array

         0   1   2   3   4   5   6   7
value = [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ]

                 0               1
dword[2] = [[] [] [] []],  [[] [] [] []]

             0        1        2        3
word[4] = [[] []], [[] []], [[] []], [[] []] 

             0     1     2     3     4     5     6     7
byte[8]  = [[ ]] [[ ]] [[ ]] [[ ]] [[ ]] [[ ]] [[ ]] [[ ]]

Однако, похоже, это не происходит так, как я ожидал.

Моя общая цель состоит в том, чтобы смоделировать шаблон, который я изложил выше, так, чтобы базовый размер регистра составлял 64 бита или 8 байтов в ширину, и с помощью объединений я мог получить доступ к суббайтам, слову или словам из полное слово.

Не могли бы вы уточнить, что мне здесь не хватает? Я не уверен, связано ли это с тем, как std::bitset хранится в памяти, связано ли это с выравниванием структур или с самими союзами.

Ответы [ 2 ]

1 голос
/ 07 мая 2019

То, что вы хотите, не может быть сделано так, как вы хотите. std::bitset не дает никаких гарантий относительно его размера, поэтому нельзя ожидать, что bitset<8> будет иметь размер в байтах. Вы также не можете получить доступ к членам этих bitset s, если они не являются активными членами профсоюза.

То, что вы хотите сделать, это:

  1. Магазин uint64_t.
  2. Доступ к различным подмножествам битов этого uint64_t через совместимый с диапазоном объект, который позволяет вам манипулировать ими.

Так что просто внедрите , что . Вам нужен не bitset, а битовый диапазон тип представления , который позволяет интерпретировать и манипулировать любой последовательной последовательностью битов в этом uint64_t как диапазоном. По сути, вам нужен интерфейс bitset, но через ссылку на хранилище (и определенный диапазон этого хранилища), а не на , являющееся хранилищем. Вы не храните эти диапазоны; вы генерируете диапазоны по запросу.

0 голосов
/ 07 мая 2019

В языковом стандарте нет ничего, что определяло бы, как bitset внутренне обрабатывает хранилище. Одна реализация, на которую я смотрел, использует массив unsigned long для хранения 32 или менее битов (unsigned long long для более 32). Это, вероятно, сделано для эффективности.

При такой схеме хранения все типы Byte, Word и DWord будут занимать четыре байта, даже если они не будут использоваться всеми. Хранение этих массивов в ваших больших объединениях приведет к увеличению размера объединения, так как в каждом битовом наборе есть неиспользуемые байты.

Чтобы устранить эти неиспользуемые байты, вам придется использовать что-то еще.

...