C语言综合3 --- 数字字节序

本文介绍了数字字节序的概念,包括大端字节序和小端字节序,以及在网络字节序和本地址字节序中的应用。在不同CPU架构下,数字的存储方式有所不同,这对于网络通讯和跨平台程序设计尤为重要。文中还提到了在小端字节序CPU中,逻辑左移位操作与数字存储字节序无关。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 前言:教学时,发现经常有一些重要的C语言知识要点,在底层开发应用广泛,但从没有一本教材详细讲解,并且有让人信服的论证.因此在教学里我把这一些要求全部总结在一起,通过学生不断反馈和补充,形成这几本文章.

-----------------------------------------------------------------------------------

数字字节序

 

Andrew Huang<bluedrum@163.com>

 

内容提要

l        数字字节序概念

l        数字字节序的测试

l        网络字节序,本地址字节序

 

不同的CPU下,数字在内存的表示是不一样的,如果要写网络通讯程序或者是在不同CPU下工作的程序,当处理数字,你必须考虑数字字节序。

      数字字节序概念

  在数学上,一个数字位数排列是有固定顺序的,即数字是低位在右,高位在左.在编程中也是遵循这样的习惯.比如数字左移,表示数字向左边移动,即低位向高位移动.进位也是由右至左依次进行.C语言里,把一个数的最高位为MSB(最高有效字节),而一个数的最低位称为LSB(最低有效位).

   C语言中,大部分数字实际上存在于内存的一个定长空间,32Bit CPU,一个整数占用了4个字节.而内存本身也是一个线性空间.即从00xFFFFFFF之类编址.内存就没有左右之分了.只有低址和高址之分.一般在绘图或调试软件里,低址也是位于左侧,高址位于右侧.

 

 

一般人的直觉是,数字在内存的存储应该是 数字的高位(MSB)在低址上,低位(LSB)在高址上.这样在内存中,数字就是按数学习惯的方法展开.

以数字0x12345678为例

 

 

计算机领域从来就不是一统天下.除了这种比较自然的存储方式.还有一种反其道而行之的表示方法.

首先我们明确一下Endian,Big-EndianLittle-Endian的概念:

端模式(Endian)的这个词出自Jonathan Swift书写的著名童话《格列佛游记》。这本书根据将鸡蛋敲开的方法不同将所有的人分为两类,从圆头开始将鸡蛋敲开的人被归为Big Endian,从尖头开始将鸡蛋敲开的人被归为Littile Endian。小人国的内战就源于吃鸡蛋时是究竟从大头(Big-Endian)敲开还是从小头(Little-Endian)敲开。在计算机业Big EndianLittle Endian也几乎引起一场战争。在计算机业界,Endian表示数据在存储器中的存放顺序。

大小模式对数据进行存放的主要区别在于在存放的字节顺序.前面所讲的比较自然一点模式,叫大端字节序(Big-Endian模式),是高字节数据(MSB)存放在低地址处,低字节数据(LSB)存放在高地址处。而小端字节序(Little-Endian)则相反.低字节数据(LSB)存放在内存低地址处,高字节数据(MSB)存放在内存高地址处;

大端模式合符人的思维,小端模式合适计算机的处理.双方各有优点,以下是Little-Endian在内存表示一个数的格式.

 

 

  大端优先模式以嵌入式CPU居多,MotorolaPowerPC系列.而小端优先以PCCPU居多,Intel X86系统.而且ARM可以配置成任一种模式.

 

  数字字节序应用

数字字节序的是关于数字如何存储的格式,而不关运算的事情.

比如数字左移操作,比如开发者都可以认为是从数字低位向高位移动,至于移动后,数字存储格式如何调整,CPU会处理其中细节.因此如果在一个CPU内部处理数字.开发者无需关心数字字节序问题

但如果牵涉到在多个CPU之间传输数字问题.如通过网络,文件和总线传输数字的话.必须要考虑到数字字节序问题.

数字字节序问题存在于2Byte或以上的字节来表示的数字中,因此char类型不存在数字字节序问题.一般只考虑shortint,long,64bit CPU下还要考虑64bit长整型的数字字节序.更长类型已经超出过一般C语言的标准了.一般无论考虑了.

 

测试字节序

1.      测试字节序的宏

 

2.      显示一个数在内存的存储格式

 

参见源码

     

      

网络字节序,本地址字节序

 

IP协议是定义在可以在任何操作系统或CPU传输数据的协议,ip传输一个数字,必须统一规定的字节序,否则在传输时会发混乱.这个统一数字字节序叫网络序.TCP/IP规定网络序采用大端字节序, 相对的, CPU本身数字表示顺序称为本机序.

IP包在发送数字之前,比如端口号之类,必须把这些数字本机序转换为网络序.在接收后,也需要把网络序数字转为本地序,这样才能让接收的CPU正常使用数字.

在各个操作系统都会要实现四个转换函数.

 

unit16_t htons(uint16_t host);

unit32_t htonl(uint32_t host);

unit16_t ntohs(uint16_t net);

unit32_t ntohl(uint32_t net);

 

 


ntohl
(将32位网络字符顺序转换成主机字符顺序)

相关函数

htonlhtonsntohs

表头文件

#include<netinet/in.h>

定义函数

unsigned long int ntohl(unsigned long int netlong);

函数说明

ntohl()用来将参数指定的32netlong转换成主机字符顺序。

返回值

返回对应的主机字符顺序。

 

 


ntohs
(将16位网络字符顺序转换成主机字符顺序)

相关函数

htonlhtonsntohl

表头文件

#include<netinet/in.h>

定义函数

unsigned short int ntohs(unsigned short int netshort);

函数说明

ntohs()用来将参数指定的16netshort转换成主机字符顺序。

返回值

返回对应的主机顺序。

 

 


htonl
(将32位主机字符顺序转换成网络字符顺序)

相关函数

htonsntohlntohs

表头文件

#include<netinet/in.h>

定义函数

unsigned long int htonl(unsigned long int hostlong);

函数说明

htonl()用来将参数指定的32hostlong 转换成网络字符顺序。

返回值

返回对应的网络字符顺序。

 

 


htons
(将16位主机字符顺序转换成网络字符顺序)

相关函数

htonlntohlntohs

表头文件

#include<netinet/in.h>

定义函数

unsigned short int htons(unsigned short int hostshort);

函数说明

htons()用来将参数指定的16hostshort转换成网络字符顺序。

返回值

返回对应的网络字符顺序。

 

使用这四个函数要注意.它们处理的对象实际上是对无符号的数字作相庆的位置换.因此不会理会是否有符号的情况,

大端优先的CPU的无需作转换,而小端优先的CPU必须作转换,一般用位直接操作.

转换代码一般如下:

 

#define ntohs (x)  {

            __u16 __x = (x);

            ((__u16)( (((__u16)(__x) & (__u16)0x00ffU) << 8) |

                        (((__u16)(__x) & (__u16)0xff00U) >> 8) ));

}

 

#define ntohl(x) {

            __u32  __x = (x);

            ((__u32)( (((__u32)(__x) & (__u32)0x000000ffUL) << 24) |

                        (((__u32)(__x) & (__u32)0x0000ff00UL) <<  8) |

                        (((__u32)(__x) & (__u32)0x00ff0000UL) >>  8) |

                        (((__u32)(__x) & (__u32)0xff000000UL) >> 24) ));

}

 

网络字节序转换的使用:

  struct sockaddr_in my_addr; 

  my_addr.sin_family = AF_INET;             

my_addr.sin_port = htons(port);                  

my_addr.sin_addr.s_addr = INADDR_ANY;  

 

数字表达与数字节序的区别联系

一般引入数字字节序后,很多人会形成一阵思维混乱,比如在小端字节序的CPU下,逻辑左移位操作。是按原始存储来移位,还是按数字本身的移位?这里要明确一点,所有数字运算和位操作(移位,或,与,异或等)都是按数字本身逻辑的排序来操作,如逻辑左移是数字低位向高位移动。与数字存储时的字节序没有关系。否则标准C程序在不同字节序CPU不是会有两种结果?但是数字位操作结果最终存储到内存中,还是由汇编语句移位操作(即CPU本身自动转换)成当前CPU字节序存放。

 

练习题

 

windows 32,请回答下列问题

 

union u1{

  unsigned long a;

  unsigned char b[4];

};

 

int main()

{

  union u1 u;

  u .a= 0x58739848;

  printf(“%x/n”,u.b[3]&0xFF);

}

 

请问屏幕打印的值是多少?

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值