今天面试被问了一个网络字节系列的问题分享一下:
1.如何将Int转换成byte数组在网络上传输。
2.计算机世界里的大小端问题。
计算机世界里为什么有大小端
硬件设计因素
- CPU 架构差异
- 不同的 CPU 架构在设计时,对于多字节数据在内存中的存储顺序有不同的考量。例如,x86 架构的 CPU 采用小端字节序,这是因为小端字节序在进行数据的低字节操作时更加方便。在 x86 架构中,数据的加载和存储操作通常从低地址开始,小端字节序使得低位字节存于低地址,在进行如加法、减法等运算时,能够直接从低地址开始处理数据,减少了额外的转换步骤,提高了硬件处理的效率。
- 而一些网络设备和早期的大型计算机系统,如 IBM 的大型机,则采用大端字节序。大端字节序符合人类阅读和书写数字的习惯,高位字节在前,低位字节在后,在进行数据的比较和显示时更加直观,便于硬件设计人员进行调试和维护。
- 内存访问效率
- 小端字节序在处理数据时,对于低位字节的访问更加高效。因为计算机在进行数据处理时,常常需要先处理数据的低位部分,小端字节序将低位字节存于低地址,使得 CPU 可以直接从低地址开始读取和处理数据,减少了地址计算和数据移位的操作,提高了内存访问的效率。
- 大端字节序在进行数据的整体比较和传输时具有优势。例如,在进行网络数据传输时,大端字节序可以直接将数据按顺序发送,接收方也可以按顺序接收和解析,避免了额外的字节序转换操作。
历史发展因素
- 早期计算机设计的影响
- 在计算机发展的早期,不同的计算机制造商和研发团队根据自己的设计理念和技术水平,选择了不同的字节序。这些早期的设计决策在后续的发展中逐渐形成了各自的标准和习惯,并且由于兼容性和成本的考虑,很难在后续的产品中进行大规模的更改。因此,不同的字节序得以保留并延续至今。
- 行业标准和规范
- 随着计算机技术的发展,不同的行业和领域逐渐形成了各自的标准和规范。例如,网络通信领域采用大端字节序作为网络字节序,这是为了确保不同的计算机系统在进行网络通信时能够正确解析数据。而在一些嵌入式系统和特定的应用场景中,可能会根据硬件平台和应用需求选择小端字节序。
不同场景下的数据处理需求
- 数据显示和比较
- 大端字节序在数据的显示和比较方面更加直观。例如,在显示一个多字节的整数时,大端字节序可以直接将高位字节显示在前面,符合人类的阅读习惯。在进行数据比较时,大端字节序也可以直接按字节顺序进行比较,无需进行额外的转换。
- 小端字节序在数据处理和运算方面更加高效。在进行数据的加法、减法等运算时,小端字节序可以直接从低位字节开始处理,减少了数据移位和地址计算的操作。
- 数据传输和存储
- 在网络数据传输中,为了确保不同的计算机系统能够正确解析数据,通常采用大端字节序作为网络字节序。这样,发送方在发送数据时将数据转换为大端字节序,接收方在接收数据后再将其转换为本地字节序,从而保证了数据的正确传输和解析。
- 在数据存储方面,不同的存储设备和文件格式可能采用不同的字节序。例如,一些图像文件格式采用大端字节序,而一些数据库系统则可能采用小端字节序。在进行数据存储和读取时,需要根据具体的存储设备和文件格式进行字节序的转换。
图示如下大小端如何存储
地址编号: 0 1 2 3 4 5 6 7
存储单元:[0x12] [0x34] [0x56] [0x78] [ ] [ ] [ ] [ ] 0X12345678 大端, 4个byte
存储单元:[0x78] [0x56] [0x34] [0x12] [ ] [ ] [ ] [ ] 0X12345678 小端, 4个byte相同的值:字节数据的存储顺序时不同的。 我们用C的伪代码来表示一下如何转换intToByteArrayuint8_t byteArr[4] = {}(0X123456789 >> 24) &&0XFF = 0X12 byteArry[0]= 0X12(0X123456789 >> 16) && 0XFF = 0X34 byteArry[1]= 0X34(0X123456789 >> 8) && 0XFF = 0X56 byteArry[2]= 0X56(0X123456789) && 0XFF = 0X89 byteArry[3]= 0X89int INT_SIZE = sizeof(int);
//下面提供C代码,大端存储
void intToByteArray(int num, unsigned char byteArray[INT_SIZE]) {for (int i = 0; i < INT_SIZE; i++) {// 右移 (INT_SIZE - 1 - i) * 8 位,将当前要提取的字节移到最低 8 位// 然后使用按位与操作符 & 0xFF 提取出最低 8 位的值byteArray[i] = (num >> ((INT_SIZE - 1 - i) * 8)) & 0xFF;}
}
大端byte转int
int byteArrayToInt(const unsigned char* bytes, size_t length) {int value = 0;for (size_t i = 0; i < length; ++i) {value |= (int)bytes[i] << ((length - 1 - i) * 8);}return value;
}//小端存储。高地址存储的是数据高位。低地址存储的是数据的地位。byte[3]存储的0x12,byte[0] = 0x89
(0X123456789) && 0XFF = 0X89 byteArry[0]= 0X89(0X123456789 >> 8) && 0XFF = 0X56
byteArry[1]= 0X56(0X123456789 >> 16) && 0XFF = 0X34
byteArry[2]= 0X34(0X123456789 >> 24) &&0XFF = 0X12
byteArry[3]= 0X12//c代码提供如下:
void intToByteArrayLittleEndian(int num, unsigned char byteArray[INT_SIZE]) {for (int i = 0; i < INT_SIZE; i++) {byteArray[i] = (num >> (i * 8)) & 0xFF;}
}int byteArrayToIntLittleEndian(const unsigned char* bytes, size_t length) {int value = 0;for (size_t i = 0; i < length; ++i) {value |= (int)bytes[i] << (i * 8);}return value;
}