问题描述
如果我用 C 编写以下代码:
int n;
n = 2864434397;
int i;
i = &n; //I kNow there will be a warning,it's ok
由于小端约定,我的堆栈中的变量 n
将是,例如:
0xffffd12c: 0xdd
0xffffd12d: 0xcc
0xffffd12e: 0xbb
0xffffd12f: 0xaa
然后,如果我查看变量 i
的值,我会看到 i = 0xffffd12c
。
这意味着程序将以这种方式读取 0xffffd12c
处的值和以下三个地址:
n == 0xAABBCCDD == [value of 0xffffd12f | value of 0xffffd12e | value of 0xffffd12d | value of 0xffffd12c]
我说得对吗?
解决方法
字节序不是由语言决定的,在您的情况下是 C,而是由您运行代码的目标 CPU 决定。因此,无论您是在 ARM 微控制器还是 x86 CPU 上运行代码,位和字节字节序都可能有所不同。
更多信息请看这里:https://en.wikipedia.org/wiki/Endianness#Hardware
,问题中的程序不包含任何从内存读取值的代码。如果编译器接受 i = &n;
,它只是将 i
设置为 n
的地址,而不读取 n
的任何字节。此外,2864434397
会溢出 int
,因此 n = 2864434397;
的结果是实现定义的。
要检查内存中的单个字节,我们可以使用:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
// Use unsigned int so we can avoid complications from a sign bit.
unsigned int n = 0xaabbccdd;
/* Use a pointer (marked with "*") to hold the address of n.
Use a pointer to unsigned char so we can address the individual bytes.
*/
unsigned char *p = (unsigned char *) &n;
// Use a loop to iterate through the number of bytes in n.
for (size_t i = 0; i < sizeof n; ++i)
// Print each unsigned char (format hhx) in n.
printf("Byte %zu is 0x%02hhx.\n",i,p[i]);
}
内存中的字节可能以AA16、BB16、CC16、DD16的顺序出现>,但它们可能会出现在其他顺序中。在我使用的 C 实现中,程序的输出是:
Byte 0 is 0xdd. Byte 1 is 0xcc. Byte 2 is 0xbb. Byte 3 is 0xaa.
2018 C 标准的第 6.2.6.1 2 段说 C 实现(主要是编译器)定义了对象的字节存储顺序,例如 int
:
除位域外,对象由一个或多个字节的连续序列组成,其数量、顺序和编码是明确指定的或实现定义的。
大多数 C 实现使用与它们所针对的计算机处理器相匹配的字节顺序。但是,有些情况并非如此:
- 有些处理器让软件选择字节序。 (字节序是指整数的“大端”(高值位)还是“小端”(低值位)存储在内存中的低字节地址。
- C 实现可能旨在支持需要特定字节顺序的旧软件。
- 对象的字节可能部分由处理器决定,部分由编译器决定。例如,在仅支持 16 位算术和 16 位加载和存储的“16 位”处理器上,编译器可能支持软件中的 32 位整数类型,但使用多条指令加载它,存储它,并做算术。在这种情况下,32 位整数可以有两个 16 位部分。 16 位部分中字节的顺序可以由处理器决定,但两部分的顺序完全取决于编译器。因此,字节可以按照 CC16、DD16、AA16、BB16 的顺序出现在内存中。