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 相乘的原因,与机器使用的位模式和顺序无关。
任何与实际位模式的相似之处,无论是活的还是死的,纯属巧合。
我在 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
上使用 gccConfigured 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 相乘的原因,与机器使用的位模式和顺序无关。
任何与实际位模式的相似之处,无论是活的还是死的,纯属巧合。