The reason for recording this article is that in an interview question, the interviewer asked questions at the big and small ends and didn't answer them. Make a note here.
Main content reference This blog.
definition
Big endian mode: the high-order bytes are arranged at the low address end of the memory, and the low-order bytes are arranged at the high address end of the memory.
Small endian mode: low order bytes are placed at the low address end of the memory, and high order bytes are placed at the high address end of the memory.
It's enough to remember one word during the interview, "small high high", that is, small end mode - high byte data - high address location.
Byte order high and low
Taking a 4-byte integer value int a = 0x12345678 as an example, the hexadecimal, decimal and binary of the number are respectively:
HEX 12345678
DEC 305,419,896
BIN 0001 0010, 0011 0100, 0101 0110, 0111 1000
Then the corresponding relationship between binary and hexadecimal digits is:
0001 0010 | 0011 0100 | 0101 0110 | 0111 1000 (binary)
0x12 | 0x34 | 0x56 | 0x78 (HEX)
High byte ------------ > low byte
Address position height
Similarly, take the 4-byte integer value a = 0x12345678 as an example. At present, the storage order of the value on the machine is not clear. However, if memory space is allocated to it, if the order of four bytes is a memory segment from 0x01 to 0x04, the memory growth order is from low address to high address.
0x0001 | 0x0002 | 0x0003 | 0x0004
Low address ------------------------- > high address
Code verification
There are two ways to check the large and small end modes on this machine.
#include <iostream> int main() { #if 1 union { int ia; char ca[4]; } un; un.ca[0] = 0x12; un.ca[1] = 0x34; un.ca[2] = 0x56; un.ca[3] = 0x78; printf("0x%x,%d\n",un.ia,sizeof(int)); if(un.ia == 0x12345678) printf("big endien\n"); else if(un.ia == 0x78563412) printf("little endien\n"); #else int ia = 0x12345678; char *ca = (char*)(&ia); printf("0x%x,%d\n",*ca,sizeof(int)); if(*ca == 0x12) printf("big endien\n"); else if(*ca == 0x78) printf("little endien\n"); #endif return 0; }
On x86 machines, it is small end mode. PowerPc machine is in big end mode. Network byte transmission adopts big end mode.
Size conversion
#include<stdio.h> typedef unsigned int uint_32 ; typedef unsigned short uint_16 ; //16 bit #define BSWAP_16(x) \ (uint_16)((((uint_16)(x) & 0x00ff) << 8) | \ (((uint_16)(x) & 0xff00) >> 8) \) //32 bit #define BSWAP_32(x) \ (uint_32)((((uint_32)(x) & 0xff000000) >> 24) | \ (((uint_32)(x) & 0x00ff0000) >> 8) | \ (((uint_32)(x) & 0x0000ff00) << 8) | \ (((uint_32)(x) & 0x000000ff) << 24) \) //Unsigned integer 16 bit uint_16 bswap_16(uint_16 x) { return (((uint_16)(x) & 0x00ff) << 8) | \ (((uint_16)(x) & 0xff00) >> 8) ; } //Unsigned integer 32-bit uint_32 bswap_32(uint_32 x) { return (((uint_32)(x) & 0xff000000) >> 24) | \ (((uint_32)(x) & 0x00ff0000) >> 8) | \ (((uint_32)(x) & 0x0000ff00) << 8) | \ (((uint_32)(x) & 0x000000ff) << 24) ; } int main(int argc,char *argv[]) { printf("------------Macro with parameters-------------\n"); printf("%#x\n",BSWAP_16(0x1234)) ; printf("%#x\n",BSWAP_32(0x12345678)); printf("------------function call-----------\n"); printf("%#x\n",bswap_16(0x1234)) ; printf("%#x\n",bswap_32(0x12345678)); return 0 ; } Output results: ------------Macro with parameters------------- 0x3412 0x78563412 ------------function call----------- 0x3412 0x78563412
The above bit operation mode can be adopted for the large and small side conversion, and htonl, htons, ntohl, ntohs and other functions can also be used for implementation. If necessary, readers can refer to the blog links placed at the beginning of this article for in-depth understanding.