青岛移动公司网站,网站建设有免费的吗,北京大兴企业网站建设咨询,丽水集团网站建设文章目录 前言一、什么是大小端二、如何判断大小端三、大小端的转换3.1 使用标准库函数3.2 手动实现大小端转换 前言
本文主要探讨计算机中大小端的相关概念以及如何进行大小端的判断和转换等。 一、什么是大小端
大小端#xff08;Endianess#xff09;是指计算机系统在存… 文章目录 前言一、什么是大小端二、如何判断大小端三、大小端的转换3.1 使用标准库函数3.2 手动实现大小端转换 前言
本文主要探讨计算机中大小端的相关概念以及如何进行大小端的判断和转换等。 一、什么是大小端
大小端Endianess是指计算机系统在存储多字节数据时字节的顺序即存储数据的字节顺序。
计算机系统的内存是以字节为单位进行划分的每个地址单元都对应着一个字节一个字节的大小为8bit可以存放一个8位的二进制数比如10101010。但是在C语言中除了8bit的char类型之外还有16bit的short类型32bit的long类型这主要取决于具体的编译器。且对于位数大于8位的处理器例如16位或者32位的处理器由于寄存器宽度大于1个字节那么必然存在着如何将多个字节安排进入内存的问题因为就产生的大端存储模式和小端存储模式。
如下所示为数据0x12345678在计算机存储器中的大小端存储模式。 大端Big Endian 数据的高位字节存放在低地址低位字节存放在高地址。 小端Little Endian 数据的低位字节存放在低地址高位字节存放在高地址。
二、如何判断大小端
以下是一些常见处理器架构及其对应的字节序大小端总结表
处理器架构字节序Intel x86Little-EndianPower-PCBig-EndianARM默认 Little-EndianSTM32Little-Endian
判断系统的字节序大小端主要依赖于检查内存中数据的排列方式例如我们可以通过定义一个联合体将一个整型数据的地址与字符数组的地址重叠从而通过查看存储顺序来判断字节序。
#include stdio.htypedef union {int i;char c[4]; // 假设 int 是 4 字节
} Endianness;int main() {Endianness e;e.i 0x01020304; // 设定一个已知的整数if (e.c[0] 0x04) {printf(小端\n);} else if (e.c[0] 0x01){printf(大端\n);}return 0;
}三、大小端的转换
在处理数据时尤其是在网络通信和文件读写中可能需要在大端Big Endian和小端Little Endian之间进行转换。以下是几种常见的大小端转换方法包括使用标准库函数和手动实现。
3.1 使用标准库函数
在许多C标准库中提供了网络字节序的转换函数可以用来进行大小端的转换。以下是几个常用的函数
htonl()将主机字节顺序转换为网络字节顺序32位整数htons()将主机字节顺序转换为网络字节顺序16位整数ntohl()将网络字节顺序转换为主机字节顺序32位整数ntohs()将网络字节顺序转换为主机字节顺序16位整数
示例代码
#include stdio.h
#include arpa/inet.hint main() {uint32_t num 0x12345678;uint32_t converted_num htonl(num); // 转换为网络字节序大端printf(Original: 0x%x\n, num);printf(Converted: 0x%x\n, converted_num);uint32_t back_to_host ntohl(converted_num); // 转换回主机字节序printf(Back to Host: 0x%x\n, back_to_host);return 0;
}编译输出如下
jeffjeff:/tmp$ gcc -o test test.c
jeffjeff:/tmp$ ./test
Original: 0x12345678
Converted: 0x78563412
Back to Host: 0x12345678
jeffjeff:/tmp$3.2 手动实现大小端转换
如果没有标准库可用可以手动实现大小端的转换以下是一个手动转换32位和16位整数的示例。
32位整数转换
uint32_t swap_uint32(uint32_t num) {return ((num 24) 0xff) | // 取出最高字节并移到最低位((num 8) 0xff00) | // 取出次高字节并移到次低位((num 8) 0xff0000) | // 取出次低位并移到次高位((num 24) 0xff000000); // 取出最低位并移到最高位
}16位整数转换
uint16_t swap_uint16(uint16_t num) {return (num 8) | (num 8);
}原理分析
这里简单讲一下32位整数的转换原理比如传进一个num 0x12345678那么我们的目的是想要输出num 0x78563412。
0x12345678 的二进制形式为 00010010 00110100 01010110 01111000
1. 取出最高字节并移到最低位
(num 24) 0xff
即
00000000 00000000 00000000 00010010
00000000 00000000 00000000 11111111结果为
00000000 00000000 00000000 000100102. 取出次高字节并移到次低位
(num 8) 0xff00
即
00000000 00010010 00110100 01010110
00000000 00000000 11111111 00000000结果为
00000000 00000000 00110100 000000003. 取出次低位并移到次高位
(num 8) 0xff0000
即
00110100 01010110 01111000 00000000
00000000 11111111 00000000 00000000结果为
00000000 01010110 00000000 000000004. 取出最低位并移到最高位
(num 24) 0xff000000
即01111000 00000000 00000000 00000000
11111111 00000000 00000000 00000000 结果为
01111000 00000000 00000000 00000000 最后再将结果进行或运算就得到0x78563412了其实说白了就是用左移、右移操作符进行数据位的移动然后用按位与提取指定数据位最后再用按位或将数据拼接在一起。
示例代码
#include stdio.h
#include stdint.h // 添加此行以包含 uint32_t 和 uint16_t 的定义uint32_t swap_uint32(uint32_t num) {return ((num 24) 0xff) |((num 8) 0xff00) |((num 8) 0xff0000) |((num 24) 0xff000000);
}uint16_t swap_uint16(uint16_t num) {return (num 8) | (num 8);
}int main() {uint32_t num32 0x12345678;uint16_t num16 0x1234;uint32_t converted32 swap_uint32(num32);uint16_t converted16 swap_uint16(num16);printf(Original 32-bit: 0x%x, Converted: 0x%x\n, num32, converted32);printf(Original 16-bit: 0x%x, Converted: 0x%x\n, num16, converted16);return 0;
}编译输出如下
jeffjeff:/tmp$ gcc -o test2 test2.c
jeffjeff:/tmp$ ./test2
Original 32-bit: 0x12345678, Converted: 0x78563412
Original 16-bit: 0x1234, Converted: 0x3412
jeffjeff:/tmp$