1.1 判断大小端机的方法
大端小端机的判断很简单,比如你有一个short型的变量a,它占用两个字节。假如你给它的赋值是0x1234,如果从低地址到高地址分别打印这两个字节为0x34和0x12,则这是一个小端机,因为0x34是0x1234的低字节,低字节放在了低地址空间;若打印顺序是0x12和0x34,那么这就是一个大端机。下边的示例证实了这一点:
-
#include <stdio.h>
-
#include <string.h>
-
-
void hex_printf(unsigned char * buff, int len)
-
{
-
for (int i = 0; i < len; i++) {
-
printf("%02hhx ", buff[i]);
-
if ((i+1) % 16 == 0) {
-
printf("\n");
-
}
-
}
-
printf("\n");
-
}
-
-
int main()
-
{
-
-
typedef struct bitbox {
-
int a;
-
short b;
-
}fo1;
-
-
fo1 foo1;
-
memset(&foo1, 0, sizeof(foo1));
-
foo1.a = 0x12345678;
-
foo1.b = 0x1234;
-
-
hex_printf(&foo1, sizeof(foo1));
-
printf("sizeof(foo1) [%zd]\n", sizeof(foo1));
-
-
return 0;
-
}
结果:gcc version 4.8.1 (GCC)
(小端机)
-
[root@192 util]# ./a.out
-
78 56 34 12 34 12 00 00
-
sizeof(foo1) [8]
(大端机)
-
[root@192 util]# ./a.out
-
12 34 56 78 12 34 00 00
-
sizeof(foo1) [8]
从结果中可以看出,小端机中a的数据是以字节为单位,将数据从低字节到高字节依次存放在内存的低地址到高地址上;而大端则是将数据从高字节到低字节依次存放在内存的低地址到高地址上。多余两个00是4字节对齐的结果。
1.2 实现一个判断是否是小端的函数
实现一个判断大小端的函数很简单,可以使用union,也可以使用强制类型转换,下边使用强制类型转换实现一个判断小端的函数。
-
#include <stdio.h>
-
#include <string.h>
-
-
int is_little_endian(void)
-
{
-
int foo = 0x01;
-
char *p = (char *)&foo;
-
return (*p == 0x01); //判断foo的低地址中的数据是否是0x01
-
}
-
-
int main ()
-
{
-
printf("is_little_endian [%d]\n", is_little_endian());
-
return 0;
-
}
结果:gcc
version 4.8.1 (GCC)
-
[root@192 util]# ./a.out
-
is_little_endian [1]
1.3 大小端对结构体中位字段的影响
最开始的时候只知道int之类的变量各字节之间在内存中的存储顺序和机器的大小端有关,最近在做一个小项目的时候突然发现大小端也会影响结构体中位字段在内存中的存储顺序。从下边的例子就可以看出其中影响:
-
#include <stdio.h>
-
#include <string.h>
-
-
void hex_printf(unsigned char * buff, int len)
-
{
-
for (int i = 0; i < len; i++) {
-
printf("%02hhx ", buff[i]);
-
if ((i+1) % 16 == 0) {
-
printf("\n");
-
}
-
}
-
printf("\n");
-
}
-
-
int main()
-
{
-
-
typedef struct bitbox {
-
unsigned char a;
-
int b;
-
unsigned short c;
-
unsigned char d:4;
-
unsigned char e:4;
-
unsigned char f:4;
-
unsigned char g:2;
-
unsigned char h:2;
-
}fo1;
-
-
fo1 foo1;
-
memset(&foo1, 0, sizeof(foo1));
-
-
foo1.a = 1;
-
foo1.b = 2;
-
foo1.c = 4;
-
foo1.d = 1;
-
foo1.e = 2;
-
foo1.f = 1;
-
foo1.g = 1;
-
foo1.h = 2;
-
-
hex_printf(&foo1, sizeof(foo1));
-
return 0;
-
}
结果:gcc version 4.8.1 (GCC)
(小端机)
-
[root@192 util]# ./a.out
-
01 00 00 00 02 00 00 00 04 00 21 91
(大端机)
-
[root@192 util]# ./a.out
-
00 00 00 01 00 00 00 02 00 04 12 16
上边的结果我们主要关注最后两个字节的打印。先看小端机的倒数第二个字节0x21,这个字节由d和e两个位字段成员组成,明显e放在了该字节的高位,而d放在了该字节的低位。这有点类似于小端机中,int变量的低字节放在了内存的低地址空间,高字节放在了内存高地址空间。因此我们可以通过这种方法来分析小端机打印的最后一个字节0x91,h = 10 , g = 01, f = 0001,按hgf的方式存放为10010001,即0x91。这样一来理解大端机就简单了,只需要按照结构体成员自身顺序组合起来就可以了。大端机打印的倒数第二个字节就是de = 0x12,倒数第一个字节就是fgh = 00010110 = 0x16。
阅读(2754) | 评论(0) | 转发(0) |