What I want to achieve is a means of converting any arbitrarily sized and formatted type to an std::bitset. Like this:
#include<bitset>
#include<bit>
#include<cstdlib>
#include<cstdint>
#include<array>
#include<iostream>
template<typename T, std::size_t SIZE = (sizeof(T) * CHAR_BIT)>
std::bitset<SIZE> as_bits(const T var) noexcept
{
if constexpr (SIZE < 32)//Size in bits
{
int32_t temp = 0;
std::memmove(&temp, &var, sizeof(T));
std::bitset<SIZE> bits = var;
return bits;
}//End if
else
{
std::bitset<SIZE> bits = std::bit_cast<std::bitset<SIZE>, T>(var);
return bits;
}//End else
}//End of as_bits
Usage:
float x = 4.5f;
std::cout << x << " as bits: " << as_bits(x) << "\n";
#pragma pack(push)
struct Y
{
std::array<int32_t, 4> z;
float x;
int8_t y;
};
#pragma pack(pop)
Y y = { {1,2,3,4}, 3.5, 'a'};
std::cout << "struct as bits: " << as_bits(y) << "\n";
std::cout << "size of bitset: " << as_bits(y).size() << " bits long.\n";
Output:
4.5 as bits: 01000000100100000000000000000000
struct as bits: 000000000000000000000000011000010100000001100000000000000000000000000000000000000000000000000100000000000000000000000000000000110000000000000000000000000000001000000000000000000000000000000001
size of bitset: 192 bits long.
This works for correctly the float but the struct when converted outputs 192 bits when it should only be 168 bits in size. What's going on I've got #pragma pack?
- How can I prevent padding? Should I even?
- Is there a way to lockout padded types using concepts or type traits?
- Is this undefined behavior?
- Does endian-ness matter?
- Is there a better way?
I'm using MSVC at the moment but a cross-platform implementation would be ideal.
On MSVC changing #pragma pack(push) to #pragma pack(push, 1) results in the following error: Error C2783 '_To std::bit_cast(const _From &) noexcept': could not deduce template argument for '__formal'
Does bit_cast require default padding and alignment?
Updated with a work around for types less than 32-bits in width.