对于我正在从事的项目,我使用幻数。该宏用于定义一个
#define BOOTSIGNATURE 0xAA55
但是,当我对生成的文件进行 HEXDUMP 处理时,应该说 AA55 它说 55 AA。
GCC 是在混淆字节顺序,还是我?该项目适用于 x86 处理器。AA 55 需要按特定顺序排列。我可以只交换字节,但我很好奇 GCC 为什么要这样做。
对于我正在从事的项目,我使用幻数。该宏用于定义一个
#define BOOTSIGNATURE 0xAA55
但是,当我对生成的文件进行 HEXDUMP 处理时,应该说 AA55 它说 55 AA。
GCC 是在混淆字节顺序,还是我?该项目适用于 x86 处理器。AA 55 需要按特定顺序排列。我可以只交换字节,但我很好奇 GCC 为什么要这样做。
0xAA55
是一个int
,所以你受制于你的机器的字节序。我会将其存储为 char 数组:
const unsigned char BOOTSIGNATURE[] = {0xAA, 0x55};
预处理器宏不会出现在编译的目标文件中——编译器根本看不到它们。如果您只是拥有它#define
并且从未在任何地方使用过它,那么就不会留下任何痕迹。
如果您在某处的代码中使用它,它可能会在指令中显示为常量(例如,将常量加载到寄存器或内存中)。如果您使用它来初始化静态数据,它将在数据段中显示为常量:
// Global variable definition
#define BOOTSIGNATURE 0xAA55
uint16_t my_global = BOOTSIGNATURE;
如果你编译上面的代码并查看数据段,它看起来像这样:
$ gcc -c test.c
$ objdump -s test.o
[...]
Contents of section .data:
0000 55aa0000 U...
如您所见,这两个字节以 little-endian 顺序存储在内存中55 AA
(前导0000
是十六进制的段偏移量)。
如果要控制数据的字节顺序,请将其存储为显式字节数组:
uint8_t my_global[] = {0xAA, 0x55};
这将始终按指定的顺序存储字节。
如果你想编写可移植的代码,你会使用函数来强制一个给定的字节顺序。例如,这些函数允许您将本机主机字节顺序中的 16 位值转换为大端或小端,具体取决于您在文件中需要的顺序。
#define BOOTSIGNATURE 0xAA55
struct bootheader {
uint16_t signature_be;
} header;
header.signature_be = htobe16( BOOTSIGNATURE);
我喜欢在具有非主机字节顺序的变量和结构元素上使用_le
or后缀。_be
由于您需要大端,您可以使用htons()
from arpa/inet.h
,但我不是该方法的忠实粉丝。我不认为名称像 一样清晰htobe16
,并且您没有用于转换为小端字节顺序的功能。
最简单的解决方案:使用十六进制值的整数形式,因此相应的二进制将产生相同的幻数!在这种情况下,这将是 43605