用户名
Email
论坛
潜水/灌水快乐,沉淀知识,认识更多同行。
ToB圈子
加入IT圈,遇到更多同好之人。
朋友圈
看朋友圈动态,了解ToB世界。
ToB门户
了解全球最新的ToB事件
博客
Blog
排行榜
Ranklist
文库
业界最专业的IT文库,上传资料也可以赚钱
下载
分享
Share
导读
Guide
相册
Album
记录
Doing
应用中心
帖子
本版
文章
帖子
ToB圈子
用户
免费入驻
产品入驻
解决方案入驻
公司入驻
案例入驻
登录
·
注册
只需一步,快速开始
账号登录
立即注册
找回密码
用户名
自动登录
找回密码
密码
登录
立即注册
首页
找靠谱产品
找解决方案
找靠谱公司
找案例
找对的人
专家智库
悬赏任务
圈子
SAAS
IT评测·应用市场-qidao123.com技术社区
»
论坛
›
软件与程序人生
›
后端开发
›
Java
›
C/C++ 判断盘算机存储器字节序(端序)的几种方式 ...
C/C++ 判断盘算机存储器字节序(端序)的几种方式
南七星之家
论坛元老
|
2024-10-3 22:08:11
|
显示全部楼层
|
阅读模式
楼主
主题
1563
|
帖子
1563
|
积分
4691
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要
登录
才可以下载或查看,没有账号?
立即注册
x
字节序分为存储器字节序和网络字节序(通常接纳大端),这里重要讨论的是主存储器字节序。
主存是存储器中的一种,为什么只讨论主存?因为编写运行在现代主流操作体系上的步伐,是没有 I/O 权限的。
主存字节序
所谓字节序就是字节分列的顺序,拿主存来说就是如果低字节存放在低地点处,就是低端字节序(小端),反之为高端字节序(大端)。拿 0x1234567 来说:
判断字节序
通过指针
既然字节序就是字节的分列顺序,那么我们把至少 2 字节的字节序列存放到主存中,如果能获取该数据的最低或最高地点的 1 字节数据,不就知道字节序了吗?对应 C/C++ 来说就是指针。
#include <stdio.h>
int main(void)
{
unsigned int i = 1;
char *ch_ptr = (char*)&i; // 创建一个指向 i 的字符(字节)指针
if (*ch_ptr)
{
printf("Little-Endian\n"); // 如果 *ch_ptr 为 1,表示最低位字节为 1,为小端
}
else
{
printf("Big-Endian\n"); // 否则为大端
}
return 0;
}
复制代码
为了保障可移植性,我这里用的是 unsigned int i,以确保每个平台都至少 2 个字节。别的数据范例甚至是数组都是可以的,没有本质的区别,都是在主存中存储相应数量的字节序列。
使用团结体(Union)
团结体答应在相同的内存位置存储不同的数据范例,并且可以通过不同的成员来检视同一块内存区域。利用该特性,我们可以在团结体中定义两个成员,其中一个成员确保为 1 字节(固然,也可以定义成数组,然后取数组中的第一个元素),而另一个成员则确保每个平台都至少为 2 字节。
#include <stdio.h>
typedef union
{
unsigned int i;
char byte;
} ByteOrder;
int main(void)
{
ByteOrder order;
order.i = 1; // 将整数 1 存储到联合体中
if (order.byte)
{
printf("Little-Endian\n"); // 如果最低位字节存储的是 1,则为小端
}
else
{
printf("Big-Endian\n"); // 否则为大端
}
return 0;
}
复制代码
如前所述,char byte 可以改为 char ch_arr[sizeof(unsigned int)] 情势的数组,然后需要将 order.byte 改为 order.ch_arr[0]。
这两种方法本质上是一样的,都是通过判断数据的低位字节在内存中的位置来判断字节序。可以根据实际环境选择其中一种方法来使用。
除了使用团结体和指针外,还有一些别的方法可以检测字节序。
位移和掩码
这种方法利用位操作(位移和掩码)来检测字节序。它不依赖于团结体,也不需要指针操作,而是直接通过数值操作来判断:
#include <stdio.h>
int main(void)
{
unsigned int i = 1; // 只有最低位是 1 的整数
if ( (i >> 0) & 1 ) // 将 i 右移 0 位后与 1 进行与操作
{
printf("Little-Endian\n");
}
else
{
printf("Big-Endian\n");
}
return 0;
}
复制代码
这种方法简朴明了,通过将整数 1(其二进制情势在小端中为 01 00 00 00,在大端中为 00 00 00 01)的最低位(最右边的位)与 1 进行与操作。如果结果为 1,那么阐明机器是小端字节序。
这种方法的好处是代码简朴,且没有使用额外的内存(如团结体或指针)。它直接通过整型数值本身的操作来确定字节序。
性能对比
团结体
:这种方法涉及访问团结体的不同成员。团结体方法的长处是直观易懂,但访问团结体成员可能导致微小的性能开销,尤其是在编译器优化不足的环境下。
指针
:这种方法涉及将一个整数的地点转换为字符指针,然后查抄具体的字节。这种方法可能轻微快一点,因为它直接操作内存,没有额外的抽象层。然而,这通常是微不足道的。
位移和掩码
:此方法使用位操作来查抄字节序。位操作服从非常高,因为它是直接在寄存器级别上进行的,没有内存访问的开销。
在大多数实际应用中,字节序的查抄通常只在步伐启动或初始化阶段进行一次,因此这里的性能差异险些可以忽略不计。即便云云,从纯粹理论和微优化的角度来看,位移和掩码方法可能是最快的,因为它避免了任何内存访问,直接在处置处罚器中完成所有操作。
然而,选择哪种方法应该基于代码的可读性、可维护性以及平台兼容性,而不仅仅是微小的性能差异。在大多数环境下,清楚和正确的代码要比微小的性能提升更加紧张。
别的方法
除了前面提到的 3 种常见方法,还可以使用一些更具体或高级的技能来检测或处置处罚字节序标题,尤其是在涉及到跨平台兼容性或网络通信时。
标准库函数
在某些编程环境中,标准库提供了函数来处置处罚字节序标题。例如,在 C 语言中,网络编程常用的库如 提供了 htonl() 和 ntohl() 函数,用于将主机字节序转换为网络字节序,或反之。这些函数主动考虑了底层平台的字节序:
#include <stdio.h>
#include <arpa/inet.h>
int main(void)
{
unsigned int x = 0x12345678;
unsigned int y = htonl(x); // 主机到网络字节序
if (y == x)
{
printf("Big-Endian\n");
}
else
{
printf("Little-Endian\n");
}
return 0;
}
复制代码
该方法不仅能判断字节序,还能在需要的时候转换字节序,非常得当网络通信中的数据交换。
编译器特定的预定义宏
一些编译器提供预定义的宏来指示目的平台的字节序。例如,GCC 和一些其他编译器可能定义了特定的宏,可以在编译时判断字节序。这种方法在编译时就确定了字节序,无需运行时检测。
GCC 和 Clang 编译器
GCC 和 Clang 通常不直接提供检测字节序的宏,但你可以根据平台或者架构特定的预定义宏来推断字节序。例如,你可以查抄是否定义了特定于某个架构的宏:
#include <stdio.h>
int main(void)
{
#if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
printf("Little-endian\n");
#elif defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
printf("Big-endian\n");
#else
printf("Unknown byte order\n");
#endif
return 0;
}
复制代码
这里使用了 GCC 和 Clang 编译器提供的 __BYTE_ORDER__ 宏以及相关的 __ORDER_LITTLE_ENDIAN__ 和 __ORDER_BIG_ENDIAN__ 宏来确定字节序。
MSVC 编译器
MSVC 编译器没有直接提供检测字节序的宏,因为 Windows 平台通常是小端字节序。如果你在使用 Visual Studio 且需要编写可移植的代码,可能需要自行定义这些宏或者使用其他方法来确定字节序。
跨平台编译
如果项目涉及不同的编译器和平台,就需要组合多种方法来使用,确保在这些宏未定义的环境下中也能够处置处罚。
#include <stdio.h>
int main(void)
{
#if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
printf("Little-endian\n");
#elif defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
printf("Big-endian\n");
#elif defined(_BIG_ENDIAN)
printf("Big-endian\n");
#elif defined(_LITTLE_ENDIAN)
printf("Little-endian\n");
#else
printf("Byte order unknown or assuming default (e.g., little-endian)\n");
#endif
return 0;
}
复制代码
常见 CPU 的字节序
大端字节序:IBM、Sun、PowerPC。
小端字节序:x86、DEC 。
ARM 体系的 CPU 则巨细端字节序通吃,具体用哪类字节序由硬件选择。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复
举报
0 个回复
倒序浏览
返回列表
快速回复
高级模式
B
Color
Image
Link
Quote
Code
Smilies
您需要登录后才可以回帖
登录
or
立即注册
本版积分规则
发表回复
回帖并转播
回帖后跳转到最后一页
发新帖
回复
南七星之家
论坛元老
这个人很懒什么都没写!
楼主热帖
MySQL并行复制(MTS)原理(完整版) ...
详讲Java开发中的六个常用API(Math,S ...
【K8S】K8S入门基础知识
软件项目管理 3.5.敏捷生存期模型 ...
云原生之 Docker篇 Docker Stack介绍及 ...
BOS EDI 项目 Excel 方案开源介绍 ...
鸿蒙到底是不是安卓?
java中Collections.addAll方法具有什么 ...
【.Net力扣刷题】第1656题:设计有序流 ...
postman结合newman生成测试报告 ...
标签云
集成商
AI
运维
CIO
存储
服务器
登录参与点评抽奖加入IT实名职场社区
下次自动登录
忘记密码?点此找回!
登陆
新用户注册
用其它账号登录:
关闭
快速回复
返回顶部
返回列表