谈谈字节序

本文探讨了字节序在网络通信及跨平台数据交换中的作用。详细介绍了Big Endian和Little Endian的区别,以及如何通过编程手段确保数据的一致性和正确性。

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

谈谈字节序

walterxia walter.xia@gmail.com

         说到字节序问题首先想到的是网络字节序(Network byte order)。不同主机之间需要通信,可能各个主机的体系结构不同,其本身存放字节的顺序是不同的,X86体系一般采用Little Endian(即低字节存放在低地址),而PowerPC相反,采用Big Endian(即高字节存放在低地址),而TCP/IP统一采用Big Endian,即所谓的网络字节序。这里的Endianness 即The attribute of a system that indicates whether integers arerepresented with the most significantbyte stored at the lowest address (big endian) or at the highest address(little endian). 其实Big Endian更加符合自然语言阅读的习惯,从左到右,从小到大。

         注意的是,只有多字节的时候,才会考虑字节序的问题,如果是字符串,就没有这个问题了。对int、uint16、uint32等多于1字节类型的数据,就需要考虑了,如果是C/C++语言来操作的话,不同平台上的编译器会根据平台来产生不同字节序来存储这里的整形数值。注意的是JAVA语言编写的程序则唯一采用big endian方式来存储数据,有意思,是不是“Write once, run anywhere”那句名言所倡导的。

         说到了跨平台,不同系统操作不同的文件,如何实现的?现流行的unicode,有UTF-8, UTF-16, UTF-32等。UTF-8以单字节为编码单位,所以不存在字节序。在UTF-16中,字节顺序记号BOM(Byte Order Mark)被放置为档案或字符串流的第一个字符,以标示在此档案或字符串流中,以所有十六位元为单位的字码的尾序(字节顺序)。如果十六位元单位被表示成大尾序,这字节顺序记号字符在序列中将呈现0xFE,其后跟着0xFF(其中的0x用来标示十六进制)。如果十六位元单位使用小尾序,这个字节序列为0xFF,其后接着0xFE。虽然字节顺序记号亦可以用于UTF-32,但这个编码很少用于传输,其规则如同UTF-16。对于已于IANA注册的字符集UTF-16BE、UTF-16LE、UTF-32BE和UTF-32LE等来说,不可使用字节顺序记号。文档开头的U+FEFF会被解释成一个(已舍弃的)"零宽度无断空白",因为这些字符集的名字已决定了其字节顺序。对于已注册字符集UTF-16和UTF-32来说,一个开头的U+FEFF则用来表示字节顺序。再比如,标签图像文件格式(Tagged Image File Format,简写为TIFF)是一种主要用来存储包括照片和艺术图在内的图像的文件格式。每个TIFF文件都是从指示字节序的两个字节开始的。“II”表示小端序、“MM”表示大端序。当然,流行的其他文档、图片、数据格式都会考虑字节序的问题。

         如何写字节序独立的程序呢?在写应用程序的时候,尤其是网络程序的时候,下面的函数或宏htons/ntohs/htonl /ntohl是被使用的。Linux 内核定义了一套宏定义来处理之间的转换, 在处理器字节序和你需要以特定字节序存储和加载的数据之间. 例如:

u32 cpu_to_le32 (u32) / u32 le32_to_cpu(u32);

有一些编程的问题有关字节序:

(1)      如何实现上述所讲的转换函数或宏

(2)      写一段C程序来判断所在的机器是什么Endian呢?

(3)      如何将一个字符串形式的IP地址转换为一个以网络字节序存放的无符号整型值 unsigned int cip2uint(char cip[]),前提:设定开发的系统为LittleEndian的,而且不能使用系统函数实现。

 

参考:

http://unicode.org/faq/utf_bom.html

http://zh.wikipedia.org/wiki/TIFF

http://www.ibm.com/developerworks/aix/library/au-endianc/index.html?ca=drs-

http://en.wikipedia.org/wiki/Endianness

http://zh.wikipedia.org/wiki/%E5%AD%97%E8%8A%82%E5%BA%8F

http://www.gnu.org/software/libc/manual/html_node/Byte-Order.html

http://oss.org.cn/kernel-book/ldd3/ch11s04.html

 

实验设计: 1.准备一台电脑和一个串口设备,如串口调试助手。 2.使用Python语言编写程序,通过串口连接电脑和串口设备,并发送二进制数据和文本数据。 3.在接收端,分别使用Python语言读取并解析二进制数据和文本数据,并进行比较。 二进制数据与文本数据的区别: 串口通信中,二进制数据和文本数据都可以通过串口发送和接收。二进制数据是由0和1组成的数据,它是计算机内部处理数据的一种方式,通常用于传输非文本数据,如图像、音频和视频等。二进制数据不可读,需要特定的程序或工具进行解析和处理。 而文本数据则是由字符组成的数据,通常用于传输文本内容,如命令、配置文件等。文本数据是可读的,可以直接在终端或文本编辑器中查看和编辑。 读取方法: 在Python语言中,使用pySerial库可以方便地进行串口通信。在发送二进制数据时,需要将数据转换为字节串并使用Serial.write()函数进行发送。在接收端,可以使用Serial.read()函数读取数据,并使用struct模块解析二进制数据。例如: ``` import serial import struct ser = serial.Serial('/dev/ttyUSB0', 9600) binary_data = struct.pack('!BBH', 0x01, 0x02, 0x1234) ser.write(binary_data) while True: data = ser.read(4) if len(data) == 4: values = struct.unpack('!BBH', data) print(values) ``` 在发送文本数据时,可以直接使用Serial.write()函数发送字符串。在接收端,可以使用Serial.readline()函数读取一行数据,并进行解析。例如: ``` import serial ser = serial.Serial('/dev/ttyUSB0', 9600) text_data = 'hello world\n' ser.write(text_data.encode()) while True: data = ser.readline().decode().strip() if data: print(data) ``` 需要注意的是,在进行串口通信时,需要注意数据的编码方式和字节序等问题,以确保数据的正确传输和解析。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值