std :: bitset的并集成员的结构填充

时间:2019-05-07 19:29:51

标签: c++ c++17 unions std-bitset struct-member-alignment

在将问题解决到this question之后,我继续扩展此版本的代码,以将以前的模板版本中的数据字段的并集与该版本合并在一起,到目前为止,我已经做到了:

main.cpp

%% No cached client session
update handshake state: client_hello[1]
upcoming handshake states: server_hello[2]
*** ClientHello, TLSv1
RandomCookie:  GMT: 1540414784 bytes = { 244, 150, 37, 122, 161, 146, 112, 42, 146, 1, 157, 89, 176, 65, 143, 62, 197, 121, 235, 202, 6, 196, 139, 184, 79, 38, 200, 208 }
Session ID:  {}
Cipher Suites: [TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA, TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_DSS_WITH_AES_256_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, TLS_EMPTY_RENEGOTIATION_INFO_SCSV]
Compression Methods:  { 0 }
Extension elliptic_curves, curve names: {secp256r1, secp384r1, secp521r1, sect283k1, sect283r1, sect409k1, sect409r1, sect571k1, sect571r1, secp256k1}
Extension ec_point_formats, formats: [uncompressed]
Extension extended_master_secret
***
[write] MD5 and SHA1 hashes:  len = 111
0000: 01 00 00 6B 03 01 5C D1   DD 40 F4 96 25 7A A1 92  ...k..\..@..%z..
0010: 70 2A 92 01 9D 59 B0 41   8F 3E C5 79 EB CA 06 C4  p*...Y.A.>.y....
0020: 8B B8 4F 26 C8 D0 00 00   1E C0 0A C0 14 00 35 C0  ..O&..........5.
0030: 05 C0 0F 00 39 00 38 C0   09 C0 13 00 2F C0 04 C0  ....9.8...../...
0040: 0E 00 33 00 32 00 FF 01   00 00 24 00 0A 00 16 00  ..3.2.....$.....
0050: 14 00 17 00 18 00 19 00   09 00 0A 00 0B 00 0C 00  ................
0060: 0D 00 0E 00 16 00 0B 00   02 01 00 00 17 00 00     ...............
main, WRITE: TLSv1 Handshake, length = 111
[Raw write]: length = 116
0000: 16 03 01 00 6F 01 00 00   6B 03 01 5C D1 DD 40 F4  ....o...k..\..@.
0010: 96 25 7A A1 92 70 2A 92   01 9D 59 B0 41 8F 3E C5  .%z..p*...Y.A.>.
0020: 79 EB CA 06 C4 8B B8 4F   26 C8 D0 00 00 1E C0 0A  y......O&.......
0030: C0 14 00 35 C0 05 C0 0F   00 39 00 38 C0 09 C0 13  ...5.....9.8....
0040: 00 2F C0 04 C0 0E 00 33   00 32 00 FF 01 00 00 24  ./.....3.2.....$
0050: 00 0A 00 16 00 14 00 17   00 18 00 19 00 09 00 0A  ................
0060: 00 0B 00 0C 00 0D 00 0E   00 16 00 0B 00 02 01 00  ................
0070: 00 17 00 00                                        ....
[Raw read]: length = 5
0000: 15 03 03 00 02                                     .....
[Raw read]: length = 2
0000: 02 28                                              .(
main, READ: TLSv1.2 Alert, length = 2
main, RECV TLSv1.2 ALERT:  fatal, handshake_failure
main, called closeSocket()
main, handling exception: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
main, called close()
main, called closeInternal(true)
Handshake failed: TLSv1, error = Received fatal alert: handshake_failure
Exception in thread "main" javax.naming.CommunicationException: Failed to initialize JNDI context, tried 2 time or times totally, the interval of each time is 0ms. 
t3s://xyz:1234: Destination 192.168.16.104, 1234 unreachable.; nested exception is: 
    javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure; No available router to destination.; nested exception is: 
    java.rmi.ConnectException: No available router to destination. [Root exception is java.net.ConnectException: t3s://xyz:1234: Destination 192.168.16.104, 1234 unreachable.; nested exception is: 
    javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure; No available router to destination.; nested exception is: 
    java.rmi.ConnectException: No available router to destination.]
    at weblogic.jndi.WLInitialContextFactoryDelegate.throwRetryException(WLInitialContextFactoryDelegate.java:467)
    at weblogic.jndi.WLInitialContextFactoryDelegate.getInitialContext(WLInitialContextFactoryDelegate.java:403)
    at weblogic.jndi.Environment.getContext(Environment.java:351)
    at weblogic.jndi.Environment.getContext(Environment.java:320)
    at weblogic.jndi.WLInitialContextFactory.getInitialContext(WLInitialContextFactory.java:119)
    at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:684)
    at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:313)
    at javax.naming.InitialContext.init(InitialContext.java:244)
    at javax.naming.InitialContext.<init>(InitialContext.java:216)

注册。h

#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.cpp

#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

输出

#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 类型的大小后,将它们与作为联合中的结构成员的实际大小进行比较。我正在尝试弄清这里到底发生了什么。

我不确定我是否正确执行sizeof计算,是否与bitset的内部存储有关?我试图了解并集上下文中的数据对齐方式作为基础类型为bitset类型的结构的成员。从标题中您可以看到它们有4种变体:std::bitsetbitset<8> = Bytebitset<16> = Wordbitset<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; 
        };
    };
};

但是,这似乎并没有像我期望的那样发生。

我的总体目标是模拟上面所表达的模式,从而使寄存器的基本大小为64位或8字节宽,并且通过使用并集,我将能够从中访问子字节,字或dword。完整的qword。

请您能详细说明我在这里缺少的内容吗?我不确定// 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] = [[ ]] [[ ]] [[ ]] [[ ]] [[ ]] [[ ]] [[ ]] [[ ]] 是否与内存中的存储方式有关,是否与结构对齐有关,或者是否与联合本身打交道。

2 个答案:

答案 0 :(得分:1)

您想要的东西无法以您想要的方式完成。 std::bitset不保证其大小,因此不期望bitset<8>具有一个字节的大小。如果这些bitset的成员不是活动的工会成员,则您也无法访问它们。

您想要做的是:

  1. 存储uint64_t
  2. 通过范围兼容的对象访问该uint64_t的比特的各个子集。

因此只需实现那个。您所需要的不是bitset,而是一种位范围视图类型,它使您可以将uint64_t中的任何连续位序列解释和操纵为一个范围。基本上,您需要bitset的接口,但是要通过对存储(以及该存储的特定范围)的引用来实现,而不是通过成为。您不存储这些范围;您可以根据要求生成范围。

答案 1 :(得分:0)

语言标准中没有规定bitset如何在内部处理存储的内容。我研究的一种实现使用unsigned long数组存储32个或更少的位(unsigned long long则存储32个以上)。这样做可能是为了提高效率。

使用这种存储方案,即使不使用全部ByteWordDWord类型,它们都将占用四个字节。将这些数组存储在较大的联合中将导致联合的大小增加,因为每个位集中都有未使用的字节。

为了消除这些未使用的字节,您将不得不使用其他内容。