【问题标题】:How C read 4 bytes numbers due to endianess?由于字节顺序,C如何读取4字节数字?
【发布时间】:2021-07-16 10:22:20
【问题描述】:

如果我用 C 编写以下代码:

  int n;
  n = 2864434397;
  int i;
  i = &n; //I know there will be a warning, it's ok

由于 little endian 约定,我的堆栈上的变量 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]

我说的对吗?

【问题讨论】:

  • I know there will be a warning, it's ok,不,不是。
  • 你似乎理解正确。
  • @Someprogrammerdude 好的,谢谢
  • @SouravGhosh 我的意思是我对字节序感兴趣,这只是一个例子
  • @QStack 不管是什么,错误的代码只不过是错误的代码,特别是那些可能导致 UB 的代码。

标签: c memory stack endianness


【解决方案1】:

字节序不是由语言决定的,在你的例子中是 C,但它是由你运行代码的目标 CPU 决定的。因此,无论您是在 ARM 微控制器还是 x86 CPU 上运行代码,位和字节字节序都可能有所不同。

更多信息请看这里:https://en.wikipedia.org/wiki/Endianness#Hardware

【讨论】:

  • 字节序实际上取决于 C 实现。大多数 C 实现使用与目标处理器匹配的字节序。但有些处理器让软件选择字节顺序。并且可以设计 C 实现来支持需要特定字节序的旧软件,即使它与目标处理器形成对比。
  • 这可能适用于某些架构,但例如 ARM Cortex M 架构的大端或小端固定在硅胶中。
  • ARM Cortex M 架构允许在架构中实现的每个处理器中选择字节顺序。然而,这不是我所说的一个例子。有一些特定的处理器模型允许软件 选择字节顺序。同一个处理器可以执行使用大端顺序的软件和使用小端顺序的软件。最终,内存中的字节顺序是 C 实现的选择。
【解决方案2】:

问题中的程序不包含任何从内存中读取值的代码。如果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 实现中,程序的输出是:

字节 0 是 0xdd。 字节 1 是 0xcc。 字节 2 是 0xbb。 字节 3 是 0xaa。

2018 年 C 标准的第 6.2.6.1 2 段说 C 实现(主要是编译器)定义了对象字节的存储顺序,例如 int

除了位域,对象由一个或多个字节的连续序列组成,其数量、顺序和编码要么明确指定,要么由实现定义。

大多数 C 实现使用与其目标计算机处理器相匹配的字节顺序。但是,有些情况并非如此:

  • 某些处理器允许软件选择字节顺序。 (字节序是指一个整数的“大端”,它的高值位,还是它的“小端”,低值位,存储在内存中的低字节地址。)
  • C 实现可能旨在支持需​​要特定字节顺序的旧软件。
  • 对象的字节可能部分由处理器确定,部分由编译器确定。例如,在仅支持 16 位算术和 16 位加载和存储的“16 位”处理器上,编译器可能在软件中支持 32 位整数类型,但使用多条指令来加载、存储它, 并做算术。在这种情况下,32 位整数可以有两个 16 位部分。 16 位部分中字节的顺序可以由处理器确定,但是这两个部分的顺序完全取决于编译器。因此字节可以按 CC16、DD16、AA16、BB16 的顺序出现在内存中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-04-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-11
    • 2012-01-24
    • 2021-03-12
    相关资源
    最近更新 更多