How do I convert between big-endian and little-end

2018-12-31 04:04发布

How do I convert between big-endian and little-endian values in C++?

EDIT: For clarity, I have to translate binary data (double-precision floating point values and 32-bit and 64-bit integers) from one CPU architecture to another. This doesn't involve networking, so ntoh() and similar functions won't work here.

EDIT #2: The answer I accepted applies directly to compilers I'm targetting (which is why I chose it). However, there are other very good, more portable answers here.

28条回答
君临天下
2楼-- · 2018-12-31 04:16

With the below given codes you can swap between BigEndian and LittleEndian easily

#define uint32_t unsigned 
#define uint16_t unsigned short

#define swap16(x) ((((uint16_t)(x) & 0x00ff)<<8)| \
(((uint16_t)(x) & 0xff00)>>8))

#define swap32(x) ((((uint32_t)(x) & 0x000000ff)<<24)| \
(((uint32_t)(x) & 0x0000ff00)<<8)| \
(((uint32_t)(x) & 0x00ff0000)>>8)| \
(((uint32_t)(x) & 0xff000000)>>24))
查看更多
余生无你
3楼-- · 2018-12-31 04:16

I am really surprised no one mentioned htobeXX and betohXX functions. They are defined in endian.h and are very similar to network functions htonXX.

查看更多
春风洒进眼中
4楼-- · 2018-12-31 04:17

I recently wrote a macro to do this in C, but it's equally valid in C++:

#define REVERSE_BYTES(...) do for(size_t REVERSE_BYTES=0; REVERSE_BYTES<sizeof(__VA_ARGS__)>>1; ++REVERSE_BYTES)\
    ((unsigned char*)&(__VA_ARGS__))[REVERSE_BYTES] ^= ((unsigned char*)&(__VA_ARGS__))[sizeof(__VA_ARGS__)-1-REVERSE_BYTES],\
    ((unsigned char*)&(__VA_ARGS__))[sizeof(__VA_ARGS__)-1-REVERSE_BYTES] ^= ((unsigned char*)&(__VA_ARGS__))[REVERSE_BYTES],\
    ((unsigned char*)&(__VA_ARGS__))[REVERSE_BYTES] ^= ((unsigned char*)&(__VA_ARGS__))[sizeof(__VA_ARGS__)-1-REVERSE_BYTES];\
while(0)

It accepts any type and reverses the bytes in the passed argument. Example usages:

int main(){
    unsigned long long x = 0xABCDEF0123456789;
    printf("Before: %llX\n",x);
    REVERSE_BYTES(x);
    printf("After : %llX\n",x);

    char c[7]="nametag";
    printf("Before: %c%c%c%c%c%c%c\n",c[0],c[1],c[2],c[3],c[4],c[5],c[6]);
    REVERSE_BYTES(c);
    printf("After : %c%c%c%c%c%c%c\n",c[0],c[1],c[2],c[3],c[4],c[5],c[6]);
}

Which prints:

Before: ABCDEF0123456789
After : 8967452301EFCDAB
Before: nametag
After : gateman

The above is perfectly copy/paste-able, but there's a lot going on here, so I'll break down how it works piece by piece:

The first notable thing is that the entire macro is encased in a do while(0) block. This is a common idiom to allow normal semicolon use after the macro.

Next up is the use of a variable named REVERSE_BYTES as the for loop's counter. The name of the macro itself is used as a variable name to ensure that it doesn't clash with any other symbols that may be in scope wherever the macro is used. Since the name is being used within the macro's expansion, it won't be expanded again when used as a variable name here.

Within the for loop, there are two bytes being referenced and XOR swapped (so a temporary variable name is not required):

((unsigned char*)&(__VA_ARGS__))[REVERSE_BYTES]
((unsigned char*)&(__VA_ARGS__))[sizeof(__VA_ARGS__)-1-REVERSE_BYTES]

__VA_ARGS__ represents whatever was given to the macro, and is used to increase the flexibility of what may be passed in (albeit not by much). The address of this argument is then taken and cast to an unsigned char pointer to permit the swapping of its bytes via array [] subscripting.

The final peculiar point is the lack of {} braces. They aren't necessary because all of the steps in each swap are joined with the comma operator, making them one statement.

Finally, it's worth noting that this is not the ideal approach if speed is a top priority. If this is an important factor, some of the type-specific macros or platform-specific directives referenced in other answers are likely a better option. This approach, however, is portable to all types, all major platforms, and both the C and C++ languages.

查看更多
唯独是你
5楼-- · 2018-12-31 04:17

Try Boost::endian, and DO NOT IMPLEMENT IT YOURSELF!

Here's a link

查看更多
人间绝色
6楼-- · 2018-12-31 04:19

Look up bit shifting, as this is basically all you need to do to swap from little -> big endian. Then depending on the bit size, you change how you do the bit shifting.

查看更多
几人难应
7楼-- · 2018-12-31 04:20

If you are doing this for purposes of network/host compatability you should use:

ntohl() //Network to Host byte order (Long)
htonl() //Host to Network byte order (Long)

ntohs() //Network to Host byte order (Short)
htons() //Host to Network byte order (Short)

If you are doing this for some other reason one of the byte_swap solutions presented here would work just fine.

查看更多
登录 后发表回答