网络字节序和主机字节序转换 “可交换操作”

#include <arpa/inet.h>
#include <stdbool.h>
#include <stdio.h>

inline bool is_little_endian(void)
{
    int a = 1;
    return *(int *)&a == a;
}

// hton 和 ntoh 函数的代码完全相同

uint32_t my_htonl(uint32_t hl)
{
    if(is_little_endian())
    {
        return  *((unsigned char *)&hl  ) << 24  |  
                *((unsigned char *)&hl+1) << 16  |
                *((unsigned char *)&hl+2) << 8   |
                *((unsigned char *)&hl+3);
    }
	else
	{
		return hl;
	}
}

uint32_t my_ntohl(uint32_t nl) // 很显然 my_htonl <=> my_ntohl
{
	if(is_little_endian())
	{
		return  *((unsigned char *)&nl  ) << 24  |
				*((unsigned char *)&nl+1) << 16	 |
				*((unsigned char *)&nl+2) << 8	 |
				*((unsigned char *)&nl+3);  	 
	}
	else
	{
		return nl;
	}
}

int main(void)
{
    uint32_t hl = 0x12345678;
    printf("%x\n", htonl(hl));
	printf("%x\n", ntohl(hl));
    printf("%x\n", my_htonl(hl));
	printf("%x\n", my_ntohl(hl));
puts("--------------------");
    
	printf("%x\n", ntohl(123456789));
	printf("%x\n", htonl(123456789));
	printf("%x\n", my_ntohl(123456789));
	printf("%x\n", my_htonl(123456789));



    return 0;
}

  ntohl() 是可交换操作,所以 htonl()  <-> ntohl();

这也很好理解 :

{1 2 3 4}  <--A--> {4 3 2 1} 

{4 3 2 1}  <--B--> {1 2 3 4} 

把数据看做一个抽象的点,可以看出A的操作 和  B的操作 是完全相同的

uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);

// 其实是两个函数:

uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);

 背景知识:

TCP/IP协议规定,网络数据流应采用大端字节序,即低地址高字节。例如上一节的UDP段格式,地址0-1是16位的源端口号,如果这个端口号是1000(0x3e8),则地址0是0x03,地址1是0xe8,也就是先发0x03,再发0xe8,这16位在发送主机的缓冲区中也应该是低地址存0x03,高地址存0xe8。

设 线性地址 布满 数轴的正半轴:

设数轴上的某段地址对于的数据为:... |0x12, 0x34, 0x56, 0x78 | 0x90, 0xAB|---->(网络中的数据流)

若把“0x12, 0x34, 0x56, 0x78 ” 这段数据看做一个int型数,它表示的数为0x12345678;  0x12所在地址为该int型数据的地址;  

     “0x90, 0xAB”                   这段看做一个short型数据,它表示的数为0x90AB;         0x90所在地址为该short型数据的地址;

大端平台下存储 同网络中数据流的顺序... | 0x12, 0x34, 0x56, 0x78 | 0x90, 0xAB |---->

则在小端平台下存储为:                  ... | 0x78, 0x56, 0x34, 0x12 | 0xAB, 0x90 | ---->

0x78所在地址为 该int型数0x12345678 数据的地址

0xAB所在地址为该short型数据0x90AB 数据的地址

结论:

小端存储中,多字节数据 沿着线性地址增长的方向,从最低位 开始存放

大端存储中,多字节数据 沿着线性地址增长的方向,从最高位 开始存放 ;(这也许是小端,大端名字的由来)

原文地址:https://www.cnblogs.com/mathzzz/p/2669816.html