GLib基础——大小端处理

概览

在计算机系统中,常以字节为单位的,每个地址单元都对应着一个字节,一个字节为 8bit。但是在C语言中除了8bit的char之外,还有16bit的short型,32bit的long型(要看具体的编译器)。另外,对于位数大于 8位的处理器,例如16位或者32位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如果将多个字节安排的问题。因此就导致了大端存储模式和小端存储模式。
我们常用的X86结构、ARM、DSP都是小端模式,而嵌入式系统开发中的KELI C51则为大端模式。有些ARM处理器还可以由硬件来选择是大端模式还是小端模式。

大小端含义

所谓的大端模式(Big Endian,简称BE),是指数据的低位(就是权值较小的后面那几位)保存在内存的高地址中,而数据的高位,保存在内存的低地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放。

所谓的小端模式(Little Endian,简称LE),是指数据的低位保存在内存的低地址中,而数据的高位保存在内存的高地址中,这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低,和我们的逻辑方法一致。

补充说明,PDP模式(PDP endian)是一种极为少见的一种模式,比如对于4字节,高位字节存储顺序分别第3、第4、第1、第2。

举例说明

假设存储地址是从0x4000开始,那么16bit宽的数0x1234分别在大小端模式下存储如下所示:

内存地址0x40000x4001
小端模式0x340x12
大端模式0x120x34

在GLIb中,LE、BE、PDP的定义分别如下:

#define G_LITTLE_ENDIAN 1234
#define G_BIG_ENDIAN    4321
#define G_PDP_ENDIAN    3412	

大小端存储模式引发的问题

对于大多数程序员而言,机器的字节存储顺序是完全不可见的,无论哪一种存储模式的处理器编译出的程序都会得到相同的结果。即对于同一段源代码,单独在小端机器上编译运行,其结果与单独在大端机器上编译运行的结果一样,尽管同一个数据在大小端格式下的内存表示有区别,但在应用程序员和用户眼里,参与算术逻辑运算、写入读出的数据却是无差别的。不过,有些情况下,字节顺序会成为问题。

  1. UNIX问题———程序可移植性问题。
  2. 阅读、解释、共享二进制数据的问题。对同一段可执行程序进行反汇编,使用反汇编器阅读机器级二进制代码时,在不同存储模式的处理器上会看到不同的结果。
  3. 网络数据传输的问题。通过网络传送二进制数据时,可能会产生高低字节翻转现象。

Glib大小端相关宏

本地与网络间转换

g_htonl与g_htons分别用于将32位、16位的本地整数转为网络字节顺序。g_ntohl、g_ntohs反过来。

g_htonl(val)
g_htons(val)
g_ntohl(val)
g_ntohs(val)

其中,h表示本地host, n表示网络network,s表示short。

各种类型整数的本地模式与大小端间的转换

Glib提供了丰富的宏用于整数在各种大小端间的转换,具体包括INT、UINT、LONG、ULONG、SIZE、INT16、UINT16、INT32、UINT32、INT64、UINT64。
提供的FROM表示从某种模式转为本地模式,TO表示从本地模式转为某种模式,具体由后面的BE或LE来确定。其中,BE表示Big-Endian大端模式,LE表示Little-Endian小端模式。

GINT_FROM_BE()GINT_FROM_LE()GINT_TO_BE()GINT_TO_LE()
GUINT_FROM_BE()GUINT_FROM_LE()GUINT_TO_BE()GUINT_TO_LE()
GLONG_FROM_BE()GLONG_FROM_LE()GLONG_TO_BE()GLONG_TO_LE()
GULONG_FROM_BE()GULONG_FROM_LE()GULONG_TO_BE()GULONG_TO_LE()
GSIZE_FROM_BE()GSIZE_FROM_LE()GSIZE_TO_BE()GSIZE_TO_LE()
GSSIZE_FROM_BE()GSSIZE_FROM_LE()GSSIZE_TO_BE()GSSIZE_TO_LE()
GINT16_FROM_BE()GINT16_FROM_LE()GINT16_TO_BE()GINT16_TO_LE()GUINT16_FROM_BE()GUINT16_FROM_LE()GUINT16_TO_BE()GUINT16_TO_LE()
GINT32_FROM_BE()GINT32_FROM_LE()GINT32_TO_BE()GINT32_TO_LE()
GUINT32_FROM_BE()GUINT32_FROM_LE()GUINT32_TO_BE()GUINT32_TO_LE()
GINT64_FROM_BE()GINT64_FROM_LE()GINT64_TO_BE()GINT64_TO_LE()
GUINT64_FROM_BE()GUINT64_FROM_LE()GUINT64_TO_BE()GUINT64_TO_LE()

补充说明

为了方便BE、LE、PDP之间的相互转换,又提供的又下述几种宏,用于相互转换。比如GUINT16_SWAP_BE_PDP(val),如果val是BE类型,则结果为PDP类型;如果val是PDP类型,则结果为BE类型。

GUINT16_SWAP_BE_PDP()GUINT16_SWAP_LE_BE()GUINT16_SWAP_LE_PDP()
GUINT32_SWAP_BE_PDP()GUINT32_SWAP_LE_BE()GUINT32_SWAP_LE_PDP()
GUINT64_SWAP_LE_BE()

上述中,swap表示交换的意思。

补充资料

巧用联合体对大小端判断

#include <glib.h>

union Endian{
    int a;
    char b;
} endian;

int main(int argc, char const *argv[]) {
    endian.a = 1;
    if (endian.b == 1) {
        g_print("little endian\n");
    } else {
        g_print("big endian\n");
    }
}
// 输出
little endian

由于共用体中的所有元素都存放在一块内存空间中,上述联合体Endian中,字符b的起始地址是从int型的起始地址对齐的。所以对一个int型的数据进行写1,如果是大端的话,char型的b就会为1,否则b就为0。

小结

总而言之,采用Little-endian模式的CPU对操作数的存放方式是从低字节到高字节,而Big-endian模式对操作数的存放方式是从高字节到低字节。

参考资料

https://blog.csdn.net/qq_33336682/article/details/88932835

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值