C struct内存存储顺序

C struct memory storage order

我在 C 中有一个结构:

typedef struct {
    char member_a;
    char member_b;
    char member_c;
    char member_d;
} mystruct;

据我了解,C 结构将其成员连续存储在内存中。如果我打印出结构的内存,我可以看到是这种情况,但看起来成员的顺序是相反的。

mystruct m;
m.member_a = 0xAA;
m.member_b = 0xBB;
m.member_c = 0xCC;
m.member_d = 0xDD;
printf("%X\n", m);

这输出:

DDCCBBAA

这是因为结构成员的值以相反的顺序存储在内存中吗? 所以内存看起来像这样,如果 m 存储在内存位置 0x00 并且每个位置的大小为 1 个字节:

内存位置 价值
0x00 0xDD
0x01 0xCC
0x02 0xBB
0x03 0xAA

C 是否总是这种情况?这个编译器是特定的吗?架构具体?其他?

在 Mac

上使用 gcc
Configured with: --prefix=/Library/Developer/CommandLineTools/usr --with-gxx-include-dir=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/4.2.1
Apple clang version 11.0.0 (clang-1100.0.33.17)
Target: x86_64-apple-darwin19.6.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin

你正在做的是技术上未定义的行为,所以编译器可以用它做任何它想做的事。

From what I understand, C structs store their members in memory contiguously.

不是真的。但是它们是按照声明的顺序存储的。

If I print out the struct's memory I can see that is the case, but it looks like the order of the members is reversed.

那是因为您使用的是小端计算机。尝试在 member_d 字段 之后 添加更多字段。您可能会得到相同的结果。但正如我所说,这是未定义的行为,因此您无法保证。

这是一个说明它的片段。

https://onlinegdb.com/uXS2sk142

#include <stdio.h>
#include <stdint.h>
#include <memory.h>

int main(void) {
    int32_t x = 0xDDCCBBAA;
    char p[4];
    memcpy(p, &x, 4);
    
    for(int i=0; i<4; i++) {
        printf("%X", p[i]);
    }
}

它在小端的机器上输出:

AABBCCDD

但是,请注意 C 编译器可以自由添加填充。所以即使内存中保证了顺序,他们的位置也不是。

相关:

Detecting endianness programmatically in a C++ program

Structure padding and packing

这里要理解的重要一点是:

整数的文本表示没有说明其内部 表示。它是象征性的。

我们接受使用基数 10 或单词的文本表示时不加思索:65534 与 sixtyfivethousandfivehundredthirtyfour 一样具有象征意义。

但 0xfffe 也是如此。 它是整数值的文本表示,恰好使用基数 16 而不是基数 10 编写。仅根据定义和定义,借用自十进制表示法,左边的数字具有更高的值。这个整数值 65534 将始终写入 0xfffe,无论内部实现它的是哪种位模式。这是 C 编程语言提供的最重要的抽象之一。这就是您总是使用左移运算符与 2 相乘的原因,与机器使用的位模式和顺序无关。

任何与实际位模式的相似之处,无论是活的还是死的,纯属巧合。