由于字节顺序,C 如何读取 4 个字节的数字?

问题描述

如果我用 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 的顺序出现在内存中。