Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Switching byte order without type punning

I Need to switch the order of bytes so that an int16 with contents (byte1, byte2) -> (byte2, byte1). I did this using a union:

union ConversionUnion
{
    uint8_t m_8[4];
    uint16_t m_16[2];
    uint32_t m_32;
};

//use
uint16_t example = 0xFFDE
ConversionUnion converter;
converter.m_16[0] = example;
std::swap(converter.m_8[0], converter.m_8[1]);
example = converter.m_16[0]; //0xDEFF

Now this does work on gcc, but i have been informed that this is undefined behavior (gcc 6.3, C++11).

Questions:

1) Is this really undefined behavior, I ask because i've seen this before in embedded code. Other stackoverflow questions seem to debate this, who's actually correct (for C++11 & C++14).

2) If this is undefined behavior, can byte order swapping be done without a bunch of bit shifting in a portable way. I really hate bit shifting, its horribly ugly.

like image 715
Stephen Eckels Avatar asked Jan 18 '26 17:01

Stephen Eckels


2 Answers

Type punning is allowed via char*, so why not just use that rather than a union?

uint16_t example = 0xFFDE;
char *char_alias = reinterpret_cast<char*>(&example);
std::swap(char_alias[0], char_alias[1]);
like image 65
David Scarlett Avatar answered Jan 21 '26 06:01

David Scarlett


Relying on undefined behavior or obscure semantics of the language (union) is not necessarily more idiomatic or easier to read. I find this loop much easier to parse:

uint32_t example = 0xc001c0de;
unsigned char *p = reinterpret_cast<unsigned char*>(&example);

for (size_t low = 0, high = sizeof(example) - 1;
     high > low;
     ++low, --high)
{
    std::swap(p[low], p[high]);
}
like image 23
user8100526 Avatar answered Jan 21 '26 06:01

user8100526



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!