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内存存储顺序的主要内容,如果未能解决你的问题,请参考以下文章