大端、小端模式,网络字节序,多字节字符、Unicode字符存储

本文深入解析字节序的概念,包括小端法与大端法的存储方式,并探讨网络字节序的定义及其在多字节字符集与Unicode编码中的应用。通过代码示例验证理论,确保在不同字节序环境下正确处理数据。

关于字节序(大端法、小端法)的定义

《UNXI网络编程》定义:
 术语“小端”和“大端”表示多字节值的哪一端(小端或大端)存储在该值的起始地址。
 小端(低字节数据)存在起始地址(低地址单元),即是小端字节序;大端存在起始地址,即是大端字节序。
 

也可以说:
1.小端法(Little-Endian) :高字节数据 存放在 高地址单元,低字节数据 存放在 低地址单元。 高高低低
2.大端法(Big-Endian)   : 高字节数据 存放在 低地址单元,低字节数据 存放在 高地址单元。 高低低高

如果我们用 OP0 表示一个32位数据的最高字节,用OP3表示一个32位数据的最低字节
那么,对于int整型数据 0x12345678 。有:
OP0 : 0x12
OP1 : 0x34
OP2 : 0x56
OP3 : 0x78
其在内存中的存放顺序为:


大端、小端模式,网络字节序,多字节字符、Unicode字符存储 - 一门 - yyimen的博客

#include <stdio.h> #include <stdlib.h> int main() { int a = 0x12345678; char *pa = (char *)&a; for (int i = 0; i < 4; i++) printf("0x%x ", *pa++ & 0xff); system("pause"); return 0; }


我的小端机器上的结果,如图:

===============================================

网络字节序

我们知道网络上的数据流是字节流,对于一个多字节数值,在进行网络传输的时候,先传递哪个字节?
也就是说,当接收端收到第一个字节的时候,它是将这个字节作为高位还是低位来处理呢?

网络字节序定义:
收到的第一个字节被当作高位看待,这就要求发送端发送的第一个字节应当是高位。
而在发送端发送数据时,发送的第一个字节是该数字在内存中起始地址对应的字节。
可见多字节数值在发送前,在内存中数值应该以大端法存放。
网络字节序说是大端字节序。
比如我们经过网络发送 0x12345678 这个整形,在80X86平台中,它是以小端法存放的,在发送前需要使用系统提供的htonl将其转换成大端法存放,如图所示。

大端、小端模式,网络字节序,多字节字符、Unicode字符存储 - 一门 - yyimen的博客

===============================================

MBCS 多字节字符集
对于多字节字符,计算机的存储方式是:
前导字节 存放在 低字节单元
跟随字节 存放在 高字节单元
这样保证了,无论在大端还是小端模式的机器上,读取字符时,前导字节都先于跟随字节被读取,
而我们在编程时一般都对当前字符进行一番判断,如果编码小于128,则当前字符为单字节字符,否则为多字节字符的前导字符,与其后的一个跟随字节一起组合开一个字符
下面是我的验证代码、截图:

#include <stdio.h> #include <stdlib.h> int main() { char *str = "华夏"; char *pa = str; while (*pa) printf("0x%x ", *pa++ & 0xff); system("pause"); return 0; }

===============================================

Unicode 字符集
Unicode 字符的编码 方式, 小端机上高高低低,大端机上高低低高

下面是我的验证代码、截图:

#include <stdio.h> #include <stdlib.h> int main() { wchar_t str[] = L"0123456789ABCDEF"; char *pa = (char *)str; for (int i = 0; i < sizeof(str); i++) printf("0x%x ", *pa++ & 0xff); system("pause"); return 0; }



<think>好的,用户的问题是关于在Qt C++中如何对QString以四个字节为单位进行大端序和小端序的转换。首先,我需要理解用户的具体需求。用户提到QString的处理,但QString本身是Unicode字符串,每个字符占两个字节,这可能与四字节的转换有关联吗?可能需要先将QString转换为字节数组,比如QByteArray,然后再处理字节序的问题。 接下来,用户要求以四个字节为单位进行转换。这意味着需要将数据分成四字节的块,每个块内部进行字节序的转换。例如,如果原始数据是0xAABBCCDD,大端存储为AA BB CC DD,而小端序则是DD CC BB AA。因此,每个四字节块需要反转字节顺序。 考虑到用户提供的引用内容,特别是引用[2]中提到的Qt UDP处理中的大小端转换和结构体的使用,可能需要使用类似的方法。例如,将QByteArray拆分为四字节的部分,对每个部分进行字节反转,然后再合并回去。 可能的步骤包括: 1. 将QString转换为UTF-8或Latin-1编码的QByteArray,确保每个字符占用一个字节,便于处理四字节对齐。 2. 检查QByteArray的长度是否为4的倍数,否则可能需要填充或者处理不完整的数据块。 3. 将QByteArray分割成四字节的块。 4. 对每个四字节块进行字节序转换,即反转字节顺序。 5. 将处理后的块重新组合成新的QByteArray。 6. 如果需要,将转换后的QByteArray转回QString,但需注意编码是否合适,避免乱码。 另外,用户可能需要在处理时考虑系统的字节序,例如使用Qt的qFromBigEndian和qFromLittleEndian函数,或者手动进行字节交换。例如,使用QDataStream来读写数据,设置字节序,然后进行转换。 需要注意的是,QString本身存储的是UTF-16编码,每个字符是两个字节,如果用户的数据是二进制数据而非文本,可能更适合使用QByteArray来处理。因此,在转换之前,需要明确数据的来源和用途,避免编码错误。 此外,用户的问题中提到四字节单位的转换,可能需要处理网络传输中的数据,例如UDP包中的大端序数据。因此,示例代码应该展示如何将QString的内容转换为四字节的大端小端格式,或者反向转换。 可能的代码步骤: - 将QString转换为QByteArray,使用特定的编码。 - 使用循环,每次处理四个字节,使用qToBigEndian或qToLittleEndian函数进行转换。 - 处理可能的填充情况,例如数据不足四字节时补零或截断。 还需要考虑跨平台的问题,确保在不同系统上字节序转换的正确性。例如,在x86架构的小端系统上,转换到大端序需要反转字节顺序。 最后,生成示例代码时,要确保代码的清晰和正确性,并进行测试。可能遇到的问题包括编码转换错误、字节对齐问题以及性能问题,特别是处理大量数据时的效率。</think>在Qt中实现QString以四字节为单位的大端序和小端序转换,需通过数据转换和字节操作完成。以下是分步实现方法: ### 一、核心思路 1. **编码转换**:将QString转换为UTF-8或Latin-1编码的二进制数据$QByteArray$,确保获得原始字节流[^2] 2. **字节序转换**:将字节流按四字节分组,使用系统函数或手动操作实现大小端转换 3. **数据重组**:将转换后的字节流重新封装为QString或QByteArray ### 二、具体实现 ```cpp #include <QtEndian> // 四字节大小端转换函数 QByteArray convertEndianness(const QString& input, bool toBigEndian) { // Step1: 转换为Latin-1编码的字节流 QByteArray byteArray = input.toLatin1(); // Step2: 保证数据长度是4的倍数(填充0x00) int padding = (4 - (byteArray.size() % 4)) % 4; byteArray.append(padding, 0x00); // Step3: 四字节分组转换 char* data = byteArray.data(); for(int i=0; i<byteArray.size(); i+=4) { quint32* value = reinterpret_cast<quint32*>(data + i); if(toBigEndian) { *value = qToBigEndian(*value); } else { *value = qToLittleEndian(*value); } } return byteArray; } // 使用示例: QString str = "ABCDabcd1234"; QByteArray bigEndianData = convertEndianness(str, true); // 转为大端序 QByteArray littleEndianData = convertEndianness(str, false); // 转为小端序 ``` ### 三、关键点说明 1. **编码选择**:使用$toLatin1()$而非$toUtf8()$,确保每个字符对应1字节,避免多字节编码干扰四字节分组[^2] 2. **字节填充**:通过补零实现四字节对齐,保证分组完整性 3. **系统函数**:采用$qToBigEndian()$/$qToLittleEndian()$函数处理字节序转换,兼容不同平台 4. **指针操作**:使用$reinterpret_cast<quint32*>$$进行四字节整型操作 ### 四、验证示例 原始数据:`"ABCD"` (0x41 0x42 0x43 0x44) - 转换为大端序:0x41 0x42 0x43 0x44(保持原样) - 转换为小端序:0x44 0x43 0x42 0x41 $$ \text{小端存储公式:}byte_n = \lfloor \frac{value}{256^{(n-1)}} \rfloor \bmod 256 $$
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值