我有一个以下类型的简单 C 程序
#include<stdio.h>
struct test{
char a;
char b;
char c;
char d;
int e;
};
void main() {
struct test mem = {0xa, 0xb, 0xc, 0xd, 0xef12};
long int *tmp = (long int *)(&mem.a);
printf("Struct in binary %p : 0x%lx\n", &mem.a, *tmp);
printf("Printing only a member %p : 0x%x\n", &(mem.e), *(int *)(&(mem.e)));
}
上述程序在大端机器上的输出如下:
二进制结构 0x7ffc1206abc0 : 0xef120d0c0b0a
仅打印成员 0x7ffc1206abc4 : 0xef12
问题是,为什么结构体的原始输出与其成员值的顺序相反?
“成员 e”的地址距结构基地址开头仍为 4 个字节..!
首先一些注意事项:
void main()
通常是 main() 的无效格式。
long int *tmp = (long int *)(&mem.a);
后跟 *tmp
是明确未定义的行为 - 程序有问题,因此任何事情都可能发生。
底层数据可能会错位,并且还存在“严格别名冲突”,这意味着访问不遵循使用指针类型取消引用内存的明确定义的方法。
对于那些不熟悉的人,这里解释了字节序的概念:什么是CPU字节序?
为了讨论的方便,让我们假设您的特定编译器允许通过某种语言扩展以明确定义的方式进行
long int
转换和取消引用。或者我们可以假设该结构没有填充,并且您将 memcpy
从该结构转换为 long
。
它似乎是一个 64 位 CPU,具有 64 位
long
和 32 位 int
(典型的现代 Linux/gcc)。
您的结构体始终在最低地址分配
a
,然后是 b
、c
、d
。该假设是可移植的,因为字节顺序不适用于字节大小的类型。
然后在小端机器上,值为
e
的 0xef12
将按照从最低地址到最高地址的字节顺序分配:0x12
、0xef
、0x00
、0x00
。整个结构看起来像:
// struct representation on little endian, lowest to highest address:
0x0a, 0x0b, 0x0c, 0x0d, 0x12, 0xef, 0x00, 0x00
如果是大端机器,
e
将从最低到最高分配:0x00
、0x00
、0xef
、0x12
。
// struct representation on big endian, lowest to highest address:
0x0a, 0x0b, 0x0c, 0x0d, 0x00, 0x00, 0xef, 0x12
现在,当您转换为某些
long int
64 位类型时,它假定该 long int
的最低值字节是小端机器上的最低地址,但在大端机器上则相反。
结果,64位小端
long
:0x0000ef120d0c0b0a
结果,64位大端
long
:0x0a0b0c0d0000ef12
结论:您使用的是小端、64 位长、32 位整数的系统。