面试 之 大小端-ip地址网络转本地 等

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;

}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

tiny丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值