C struct内存存储顺序

Posted

技术标签:

【中文标题】C struct内存存储顺序【英文标题】:C struct memory storage order 【发布时间】:2021-08-27 20:54:01 【问题描述】:

我在 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 个字节:

memory location value
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

【问题讨论】:

%X 格式说明符需要unsigned int,但您通过了mystruct。这会调用未定义的行为,允许任何事情发生。 这个特定结果的原因看起来像你在 little-endian 机器上。 更具体地说,它们以 AA BB CC DD 的形式存储在内存中,但在 Little Endian 机器上被视为单个整数时,这意味着 0xDDCCBBAA(例如,最低有效位、小端、首先存储)。如果你按字节循环,你会看到你所期望的。 是的,内存是连续的。是的,连续内存空间内的确切布局可能因平台和架构而异。只要您不做出任何无效的假设,就不应该有任何问题或冲突。 这能回答你的问题吗? Detecting endianness programmatically in a C++ program 【参考方案1】:

您所做的是技术上未定义的行为,因此允许编译器对其进行任何操作。

据我了解,C 结构将其成员连续存储在内存中。

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

如果我打印出结构的内存,我可以看到是这种情况,但看起来成员的顺序是颠倒的。

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

这是一个说明它的sn-p。

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

【讨论】:

添加太多字段可能会让编译器决定将结构作为指针传递并更改结果。 @MikeCAT 澄清了一下它是 ub klutt 感谢您的回复。您和@MikeCAT 都提到(其他评论部分中的MikeCAT)我正在做的是“未定义的行为”,这回答了我的问题。听起来,如果我希望结构的成员在内存中以特定顺序连续,我需要将它们显式复制到缓冲区,我不能依赖结构本身。 @northsideknight 类似的东西 @JohnBollinger 谢谢。修好了。【参考方案2】:

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

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

我们接受,无需再考虑使用以 10 为基数的文本表示,或单词:65534 与六万五千五百分之一一样具有象征意义。

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

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

【讨论】:

以上是关于C struct内存存储顺序的主要内容,如果未能解决你的问题,请参考以下文章

C语言精要总结-内存地址对齐与struct大小判断篇

C/C++ struct/class/union内存对齐

struct结构体内存大小

转C/C++ struct/class/union内存对齐

c语言问题:c语言中二维数组在内存中怎样存储?

Go Web:数据存储——内存存储