Large and small end mode

Posted by willeadie on Wed, 12 Jan 2022 12:31:28 +0100

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.

Topics: C++