Switching byte order without function

I need to switch the byte order to int16 with content (byte1, byte2) -> (byte2, byte1). I did it with a join:

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

      

This now works on gcc, but I was informed that this behavior is undefined (gcc 6.3, C ++ 11).

Questions:

1) This is indeed undefined behavior, I ask because I have seen this before in inline code. Other questions from stackoverflow seem to be discussing this, who is actually fixing it (for C ++ 11 and C ++ 14).

2) If this behavior is undefined, it is possible to perform byte byte swapping without confusing bit carry in a portable way. I really hate bit bias, its terribly ugly.

+3


source to share


3 answers


The punning type is allowed through char*

, so why not just use that rather than concatenation?



uint16_t example = 0xFFDE;
char *char_alias = reinterpret_cast<char*>(&example);
std::swap(char_alias[0], char_alias[1]);

      

+4


source


Relying on undefined behavior or obscure language semantics (union) is not necessarily more idiomatic or easier to read. I find this loop is 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]);
}

      

+2


source


  • People disagree to some extent about this. I think that

    it undefined behavior

    but my opinion is not a valuable addition.

  • Swapping bytes is simple with unsigned types (signed BTW bytes don't make sense). Just extract the individual bytes and rearrange them. Hide the ugliness in a function constexpr

    or macro.

    constexpr uint16_t bswap(uint16_t value);
    {
        uint16_t high_byte = (value >> 8) & 0xff;
        uint16_t low_byte = value & 0xff;
        return (low_byte << 8) | high_byte;
    }
    
          

By the way, if you see something in the inline code and it works, it is not an indicator that it is safe! Inline code often sacrifices portability for efficiency, sometimes using undefined behavior where it was the only way to convince a particular compiler to generate efficient code.

+1


source







All Articles