0、为什么会有大小端模式之分呢?
这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为 8bit。但是在C语言中除了8bit的char之外,还有16bit的short型,32bit的long型,另外,对于位数大于 8位的处理器,例如16位或者32位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如何将多个字节安排的问题。因此就导致了大端存储模式和小端存储模式。
1、一般 x86 都是小端 模式 ,x64有大小端
0x12345678
是一个 32 位整数,其二进制表示如下:
1100010 00110100 01010110 01111000
在计算机中,数的字节顺序是从最高位(MSB)到最低位(LSB)。因此,这个数的字节表示如下:
1100010 00110100 01010110 01111000
MSB 0x12 0x34 0x56 0x78 LSB
在大端模式下,最高字节(MSB)对应着最低的内存地址,而最低字节(LSB)对应着最高的内存地址。因此,如果你将这个数存储在以 0x10
开始的一系列地址中,你会得到:
地址 | 数据
-----------------
0x10 | 0x12
0x11 | 0x34
0x12 | 0x56
0x13 | 0x78
在小端模式下,情况正好相反,最低字节对应最低地址,最高字节对应最高地址。所以在小端模式下,存储这个数你会得到:
地址 | 数据
-----------------
0x13 | 0x78
0x12 | 0x56
0x11 | 0x34
0x10 | 0x12
3、
#include<stdio.h>
int main()
{
short int x;
char x0,x1;
x=0x1122;
x0=((char *)&x)[0]; //低地址单元
x1=((char *)&x)[1]; //高地址单元
printf("x0=0x%x,x1=0x%x\r\n",x0,x1);// 若x0=0x11,则是大端; 若x0=0x22,则是小端......
// 网络序默认大端 存储 0x11 22 ==》0x1122
short int sp = htons(x); // 主机序--》网络序
printf("sp =%x\r\n", sp); //小端机器: 则结果0x22 11
short int dp = ntohs(sp);
printf("dp =%x\r\n", dp); //小端机器: 则结果0x11 22
return 0;
}
4、
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
int main(int argc, char* argv[])
{
struct in_addr addr1,addr2;
ulong l1,l2;
l1= inet_addr("172.25.184.141");
l2 = inet_addr("211.100.21.179");
printf("l1=%lu, l2=%lu\n", l1, l2);
#if 0 //两种表示方式, in_addr 里面是一个联合体
memcpy(&addr1, &l1, 4);
memcpy(&addr2, &l2, 4);
#else
addr1.s_addr = l1;
addr2.s_addr = l2;
#endif
printf("%s : %s\n", inet_ntoa(addr1), inet_ntoa(addr2)); //注意这一句的运行结果 拆分写 内
部静态
printf("%s\n", inet_ntoa(addr1));
printf("%s\n", inet_ntoa(addr2));
unsigned int test = 0x8db819af; // 172.25.184.141 的 十六进制表示,因为小端 所以异位
printf("%u\n", test);
char sp[4] = {'\0'};
sp[0] = 0xaf;
sp[1] = 0x19;
sp[2] = 0xb8;
sp[3] = 0x8d;
printf("sp=%s\n", sp);
unsigned int test2 = *((unsigned int *)(sp));
printf("%u\n", test2);
return 0;
}
结果:
资料补充:
htons 把unsigned short类型从主机序转换到网络序
htonl 把unsigned long类型从主机序转换到网络序
ntohs 把unsigned short类型从网络序转换到主机序
ntohl 把unsigned long类型从网络序转换到主机序
struct sockaddr_in {
short int sin_family; /* 地址族 */
unsigned short int sin_port; /* 端口号 */
struct in_addr sin_addr; /* Internet地址 */
unsigned char sin_zero[8]; /* 与struct sockaddr一样的长度 */
};
struct in_addr就是32位IP地址。
struct in_addr {
unsigned long s_addr;
};
或:
struct in_addr {
union {
struct { u_char s_b1,s_b2,s_b3,s_b4;} S_un_b;
struct { u_short s_w1,s_w2;} S_un_w;
u_long S_addr;//成员s_addr为长整形结构
} S_un;
}