How can I reorder the bytes of an integer?

此生再无相见时 提交于 2019-11-30 22:09:18

These are not standard function (these are gcc extensions), but you may be able to use them:

— Built-in Function: uint16_t __builtin_bswap16 (uint16_t x) Returns x with the order of the bytes reversed; for example, 0xaabb becomes 0xbbaa. Byte here always means exactly 8 bits.

— Built-in Function: uint32_t __builtin_bswap32 (uint32_t x) Similar to __builtin_bswap16, except the argument and return types are 32 bit.

— Built-in Function: uint64_t __builtin_bswap64 (uint64_t x) Similar to __builtin_bswap32, except the argument and return types are 64 bit.

If you can use these, chances are it will result in more optimal code for your platform, if not, good job, submit a patch to gcc :)

Clang also has __builtin_bswap16() __builtin_bswap32() __builtin_bswap64()

Visual Studio

unsigned short _byteswap_ushort (
   unsigned short val
);
unsigned long _byteswap_ulong (
   unsigned long val
);
unsigned __int64 _byteswap_uint64 (
   unsigned __int64 val
);

ICC has _bswap16, _bswap and _bswap64 *need further reference

This one of the functions I wrote for the Parrot VM, you can download byteorder.c from parrotcode.org. There are probably shorter ways to do it, but this works for different size integers, and we had a macro to detect the byteorder of the platform in PARROT_BIGENDIAN, you can discard all that. Also, as mentioned above, you can search out htonl() which is a nop on bigendian hardware, but converts on little endian (just grab a Linux x86 implementation)

INTVAL
fetch_iv_le(INTVAL w)
{
    ASSERT_ARGS(fetch_iv_le)
#if !PARROT_BIGENDIAN
    return w; // No-op on little endian hardware
#else
#  if INTVAL_SIZE == 4
    return (w << 24) | ((w & 0xff00) << 8) | ((w & 0xff0000) >> 8) | (w >> 24);
#  else
#    if INTVAL_SIZE == 8
    INTVAL r;

    r = w << 56;
    r |= (w & 0xff00) << 40;
    r |= (w & 0xff0000) << 24;
    r |= (w & 0xff000000) << 8;
    r |= (w & 0xff00000000) >> 8;
    r |= (w & 0xff0000000000) >> 24;
    r |= (w & 0xff000000000000) >> 40;
    r |= (w & 0xff00000000000000) >> 56;
    return r;
#    endif
#  endif
#endif
}
sampathsris

Take a look at this answer: https://stackoverflow.com/a/105339/1461424

If you're using Visual C++ do the following: You include intrin.h and call the following functions:

For 16 bit numbers:

unsigned short _byteswap_ushort(unsigned short value);

For 32 bit numbers:

unsigned long _byteswap_ulong(unsigned long value);

For 64 bit numbers:

unsigned __int64 _byteswap_uint64(unsigned __int64 value);

8 bit numbers (chars) don't need to be converted.

Also these are only defined for unsigned values they work for signed integers as well.

For floats and doubles it's more difficult as with plain integers as these may or not may be in the host machines byte-order. You can get little-endian floats on big-endian machines and vice versa.

Other compilers have similar intrinsics as well.

In GCC for example you can directly call:

   uint16_t __builtin_bswap16 (uint16_t x)
   uint32_t __builtin_bswap32 (uint32_t x)
   uint64_t __builtin_bswap64 (uint64_t x)

This is my sample. It reverses the endianess of an integer. Notice that C doesn't specify the size of int. It could be 16, 32, 64 ... Using the (uint_16t, uint_32t, uint_64t) instead if you want to ensure the size,

void reverse_endianess(int* number)
{
    char byte_arr[8] = {0};
    int i;

    for (i=0; i < sizeof(int); i++) {
        byte_arr[i] = (*number & 0xFF);
        *number = *number >> 8;
    }

    *number = 0;

    for (i=0; i < sizeof(int); i++) {
        *number |=  byte_arr[i];
        *number = *number << 8;
    }
}
Kenneth Aalberg

You may want to have a look at this answer, which shows how to convert both ways, also with different byte sizes. This is one way to do it, but more efficient ways are discussed in the thread linked.

uint32_t num = 9;
uint32_t b0,b1,b2,b3,b4,b5,b6,b7;
uint32_t res = 0;

b0 = (num & 0xf) << 28;
b1 = (num & 0xf0) << 24;
b2 = (num & 0xf00) << 20;
b3 = (num & 0xf000) << 16;
b4 = (num & 0xf0000) << 12;
b5 = (num & 0xf00000) << 8;
b6 = (num & 0xf000000) << 4;
b7 = (num & 0xf0000000) << 4;

res = b0 + b1 + b2 + b3 + b4 + b5 + b6 + b7;

printf("%d\n", res);
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!