我理解C中的结构概念。我也理解结构如何存储在内存中。所以我创造了以下内容:
struct tag1 {
char a;
int b;
}var1;
结构的大小是8个字节(以gcc为单位)。
内存布局示例。
-----------
| | | | | ---> char a (only 1 byte is used and remaining 3 bytes are padding)
-----------
| | | | | ---> int b (4 byte is used)
-----------
现在我对这个示例程序有些怀疑。嵌套结构如何存储在内存中。
struct tag1{
int a;
struct tag2{
long b;
}var1;
}var2;
答案 0 :(得分:6)
如注释中所述,内存中结构的确切布局是特定于实现的。通常也是如此,布局受成员类型,内存寻址(32位或64位)和pragma pack
调用的影响,这些调用调整了沿内存边界对齐的方式。
当我将原始结构的两个实例作为子结构成员放入另一个结构(用于上下文,并且用于)时,我在系统上看到的一个示例 强制连续内存分配),然后将值赋给该结构的实例,以在内存布局中提供可区分的(非零)内容:
(32位寻址,没有编译语句)
typedef struct tag1{
int a;
struct tag2{
long b;
}var1;
}var2;
typedef struct {
var2 s1;
var2 s2;
}S;
主要:
S x = {0};
x.s1.a = 1;
x.s1.var1.b = 2;
x.s2.a = 3;
x.s2.var1.b = 4;
第一行图片中描述的struct S
内存:
请注意,由于struct或甚至是子结构构造,直接不需要额外的内存使用量。但间接, alignment padding 可能需要(通常会有)额外的内存。当结构定义中包含的数据类型具有不同的大小并且不会沿着寻址边界自然对齐时,会发生这种情况。发生这种情况时,填充将影响计算出的sizeof
a struct
。
您可以看到原始结构的每个实例的大小为8(两个实例为16),因为int
和long
两者都完全对齐(并且大小相同)例如,似乎没有填充。如果将long
替换为long long
,则不再是这种情况。几乎肯定需要填充。
为了提供以下信息的上下文,我机器上的相关数据大小(编译为32位)是:
int sizeChar = sizeof(char); //1 (always)
int sizeInt = sizeof(int); //4
int sizeLong = sizeof(long); //4
int sizeLL = sizeof(long long);//8
将会有更明显的填充证据和使用更广泛类型的编译指示的影响。以下结构包含4种数据类型:
typedef struct tag1 {
char a;
int b;
long c;
long long d;
}var1;
使用此结构定义,查看使用pragma pack
调用导致的填充的差异很有意思。在我的机器上,并编译32位内存映射,这是我看到的:
顺便说一句,讨论 here 涵盖了本主题中的相关要点。
答案 1 :(得分:2)
嵌套结构如何存储在内存中?
struct tag1{
int a;
struct tag2{
long b;
}var1;
}var2;
首先,您需要检查机器字大小(即32位/ 64位)和&在哪个gcc编译器上安装。根据体系结构,变量内存分配将有所不同。 sizeof 运算符将根据系统特定返回变量大小。
例如(带填充)变量存储在内存中
在32位机器int& long都分配4个字节。
| var2.var1.b | ==> 0x601058
| var2.a | ==> 0x601054
64位机器中的int分配4字节& long分配8个字节。
| var2.var1.b | ==> 0x601058
| var2.a | ==> 0x601050
此处解释了结构成员的内存对齐Alignment in c
答案 2 :(得分:0)
要弄清楚嵌套结构如何存储在内存中,您可以运行以下代码:
#include <stdio.h>
#include <limits.h>
#include <stddef.h>
struct tag1{
int a;
struct tag2{
long b;
} var1;
} var2;
int main(void){
printf("CHAR_BIT is\t\t\t\t%d\n", CHAR_BIT);
puts("");
printf("sizeof var2 is\t\t\t\t%zu\n", sizeof var2);
printf("sizeof var2.var1 is\t\t\t%zu\n", sizeof var2.var1);
printf("sizeof var2.var1.b is\t\t\t%zu\n", sizeof var2.var1.b);
puts("");
printf("offsetof(struct tag1, a) is\t\t%zu\n", offsetof(struct tag1, a));
printf("offsetof(struct tag1, var1) is\t\t%zu\n", offsetof(struct tag1, var1));
printf("offsetof(struct tag1, var1.b) is\t%zu\n", offsetof(struct tag1, var1.b));
printf("offsetof(struct tag2, b) is\t\t%zu\n", offsetof(struct tag2, b));
return 0;
}
我要求您在实施时运行此代码,而不是直接给出答案,因为:
sizeof (long) == 1
和CHAR_BIT == 32
?#pragma pack(n)
在我的实现(OS X下的clang)中,输出为:
CHAR_BIT is 8
sizeof var2 is 16
sizeof var2.var1 is 8
sizeof var2.var1.b is 8
offsetof(struct tag1, a) is 0
offsetof(struct tag1, var1) is 8
offsetof(struct tag1, var1.b) is 8
offsetof(struct tag2, b) is 0
嗯,这里看起来并不整洁,但在我的屏幕上显示时格式很好。
所以(对于我的实现)struct tag1
的内存布局将是这样的:
-----------------------
| | | | | | | | | ---> int a (8 bytes are used)
-----------------------
| | | | | | | | | ---> struct tag2 / long b (8 bytes are used)
-----------------------