Search code examples
c++outputc++17std-bitset

Why are the bit patterns not matching with the use of std::bitset


While I was unit testing my class and its constructors I noticed something peculiar with my outputs.

#include <bitset>
#include <cstdint>
#include <iostream>
#include <vector>

typedef std::uint8_t u8;
typedef std::uint16_t u16;
typedef std::uint32_t u32;
typedef std::uint64_t u64;

struct Reg8 {
    std::bitset<8> bits;
    u8 value;

    Reg8() : value{0}, bits{value} {}

    explicit Reg8( u8 val) : value{val}, bits{value} {}
    explicit Reg8(u16 val) : value{static_cast<u8>(val)}, bits{value} {}
    explicit Reg8(u32 val) : value{static_cast<u8>(val)}, bits{value} {}
    explicit Reg8(u64 val) : value{static_cast<u8>(val)}, bits{value} {}    
};

int main() {
    u8  val8  = 24;
    u16 val16 = 24;
    u32 val32 = 24;
    u64 val64 = 24;

    Reg8 r8a(val8);
    Reg8 r8b(val16);
    Reg8 r8c(val32);
    Reg8 r8d(val64);

    std::cout << "Reg8(u8)  r8a value = " << +r8a.value << '\n';
    std::cout << "Reg8(u8)  r8a bits  = " << r8a.bits << "\n\n";

    std::cout << "Reg8(u16) r8b value = " << +r8b.value << '\n';
    std::cout << "Reg8(u16) r8b bits  = " << r8b.bits << "\n\n";

    std::cout << "Reg8(u32) r8c value = " << +r8c.value << '\n';
    std::cout << "Reg8(u32) r8c bits  = " << r8c.bits << "\n\n";

    std::cout << "Reg8(u64) r8d value = " << +r8d.value << '\n';
    std::cout << "Reg8(u64) r8d bits  = " << r8d.bits << "\n\n";

    std::bitset<8> bitsA{ val8 };
    std::cout << "bits value  = " << bitsA.to_ullong() << '\n';
    std::cout << "bits binary = " << bitsA << "\n\n";

    std::bitset<8> bitsB{ val16 };
    std::cout << "bits value  = " << bitsB.to_ullong() << '\n';
    std::cout << "bits binary = " << bitsB << "\n\n";

    std::bitset<8> bitsC{ val32 };
    std::cout << "bits value  = " << bitsC.to_ullong() << '\n';
    std::cout << "bits binary = " << bitsC << "\n\n";

    std::bitset<8> bitsD{ val64 };
    std::cout << "bits value  = " << bitsD.to_ullong() << '\n';
    std::cout << "bits binary = " << bitsD << "\n\n";

    return EXIT_SUCCESS;
}

Here is my output coming from a little endian machine and Intel Quad Core Extreme running Windows 7 x64 and using Visual Studio 2017 CE in x64 debug mode with compiler language options set to c++ latest draft standard. All other compiler flags - optimizations etc Visual Studio's defaults.

Reg8(u8)  r8a value = 24
Reg8(u8)  r8a bits  = 11001100

Reg8(u16) r8b value = 24
Reg8(u16) r8b bits  = 11001100

Reg8(u32) r8c value = 24
Reg8(u32) r8c bits  = 11001100

Reg8(u64) r8d value = 24
Reg8(u64) r8d bits  = 11001100

bits value  = 24
bits binary = 00011000

bits value  = 24
bits binary = 00011000

bits value  = 24
bits binary = 00011000

bits value  = 24
bits binary = 00011000

So why do the bit patterns from the class construction not match that of the ones declared in main?

I'm using the same variable types and values to initialize the bitset that is in main as well as the one in my class yet their bit patterns don't match up. All of the ones in the class are the same, all the ones outside of the class are the same.

What I'm expecting to see and my desired values should be that of the ones seen in main. When I look at the bottom half of the output these bitset variables in main have the value of 24 and their bit patterns match that of 24 for 8 bits.

0001 1000 = 24

However the bit pattern that is stored in the bitset within my class does not match but contains the appropriate value. The bitset stored in my class has bitt pattern

1100 1100  ... doesn't = 24 in binary

What is going on here?


Solution

  • Remember that a member initialization list initializes in declaration order. Meaning that for:

    struct Reg8 {
        std::bitset<8> bits; // <- first to be initialized in mem-init-list
        u8 value; // <- second
    
    };
    

    And taking this constructor as an example:

    explicit Reg8(u16 val) : value{static_cast<u8>(val)}, bits{value} {}
    

    The order of the initialization list doesn't matter. bits comes before value in the declaration so bits will be initialized first. It will be initialized to value which is still uninitialized as value{static_cast<u8>(val)} comes after the initialization of bits.

    To fix this, swap the declaration around:

    struct Reg8 {
        u8 value;
        std::bitset<8> bits;
    };
    

    Side note: You're missing a stdint include in your code.