简体   繁体   English

c中嵌套结构的内存布局

[英]Memory layout for nested structure in c

I understand the structure's concept in C. I also understand how the structure is stored in memory. 我理解C中的结构概念。我也理解结构如何存储在内存中。 So I have created follwoing stuff: 所以我创造了以下内容:

  struct tag1 {
      char a;
      int b;
  }var1;

The size of the structure is 8 bytes(in gcc). 结构的大小是8个字节(以gcc为单位)。

Memory layout example. 内存布局示例。

 -----------
|  |  |  |  | ---> char a (only 1 byte is used and remaining 3 bytes are padding)
 -----------
|  |  |  |  | ---> int b (4 byte is used)
 -----------

Now i have some doubt in this sample program. 现在我对这个示例程序有一些疑问。 How the nested structure is stored in memory. 嵌套结构如何存储在内存中。

  struct tag1{
      int a;
      struct tag2{
          long b;
      }var1;
  }var2;

As noted in comments, the exact layout of a struct in memory is implementation specific. 如注释中所述,内存中结构的确切布局是特定于实现的。 Also generally true, layout is affected by member types, memory addressing (32bit or 64bit) and pragma pack calls that adjust the way alignment occurs along memory boundaries. 通常也是如此,布局受成员类型,内存寻址(32位或64位)和pragma pack调用的影响,这些调用调整了沿内存边界进行对齐的方式。

An example of what I see on my system when I place two instances of your original struct as sub-struct members into yet another struct (for context, and to force contiguous memory assignment), then assigned values to an instance of that struct to provide distinguishable (non-zero) content in the memory layout: 当我将原始结构的两个实例作为子结构成员放入另一个结构(用于上下文,并强制连续的内存赋值)时,我在系统上看到的一个示例 ,然后将值分配给该结构的实例以提供内存布局中可区分(非零)的内容:
(32bit addressing, with no pragma statements) (32位寻址,没有编译指示)

typedef struct tag1{
      int a;
      struct tag2{
          long b;
      }var1;
}var2;

typedef struct {
    var2 s1;
    var2 s2;
}S;

In main: 主要:

 S x = {0};

  x.s1.a = 1;
  x.s1.var1.b = 2;
  x.s2.a = 3;
  x.s2.var1.b = 4;

Memory for struct S depicted on first line of image: 第一行图​​像上描述的struct S内存:

在此输入图像描述

Note there is no additional memory usage required directly due to the struct or even sub-struct constructs. 请注意,由于struct或甚至是子结构构造,不需要直接使用额外的内存。 But indirectly , there can be (and often will be) additional memory required for alignment padding . 间接地对齐填充可能需要(通常会有)额外的内存。 This occurs when data types contained in the struct definition are of differing sizes and do not align naturally along addressing boundaries. 当结构定义中包含的数据类型具有不同的大小并且不会沿着寻址边界自然对齐时,会发生这种情况。 When this occurs, padding will effect the computed sizeof a struct . 发生这种情况时,填充影响struct的计算sizeof

You can see that the size of each instance of your original struct is 8, (16 for two instances) and because int and long both align perfectly (and are the same size) in this instance, there appears to be no padding. 您可以看到原始结构的每个实例的大小为8(两个实例为16),并且因为intlong在这个实例中完全对齐(并且大小相同),所以似乎没有填充。 If long were replaced with long long this would no longer be the case. 如果long用更换long long ,这将不再是这种情况。 Padding would almost certainly be required. 几乎肯定需要填充。

To provide context for the information below, relevant data sizes on my machine (compiled for 32bit) are: 为了提供以下信息的上下文,我的机器上的相关数据大小(编译为32位)是:

int sizeChar = sizeof(char);     //1 (always)
int sizeInt  = sizeof(int);      //4
int sizeLong = sizeof(long);     //4
int sizeLL   = sizeof(long long);//8

There will be more visible evidence of padding and the effects of pragma using a wider range of types. 将有更明显的填充证据和使用更广泛类型的pragma的影响。 The following struct contains 4 data types: 以下结构包含4种数据类型:

 typedef struct tag1 {
      char a;
      int b;
      long c;
      long long d;
  }var1;

Using this struct definition, it is interesting to view the difference in padding caused by using pragma pack calls. 使用此结构定义,有趣的是查看使用pragma pack调用导致的填充的差异。 On my machine, and compiling for 32bit memory mapping, here is what I see: 在我的机器上,并编译32位内存映射,这是我看到的:

在此输入图像描述

By the way, there is a discussion here covering related points in this topic. 顺便说一句,有一个讨论, 这里本主题涵盖相关穴位。

How the nested structure is stored in memory? 嵌套结构如何存储在内存中?

struct tag1{
      int a;
      struct tag2{
          long b;
      }var1;
  }var2;

First of all you need to check the machine word size (ie either 32-bit/64-bit) & on which gcc compiler is installed. 首先,您需要检查机器字大小(即32位/ 64位)和安装的gcc编译器。 Depending upon the architectures, the variables memory allocation will be varying. 根据体系结构,变量内存分配将有所不同。 sizeof operator will return the variables size according to system specific. sizeof运算符将根据系统特定返回变量大小。

For example(with padding) variables stored in memory 例如(带填充)变量存储在内存中

in 32-bit machines int & long both are allocating 4-bytes. 在32位机器中,int和long都分配4个字节。

|var2.var1.b|==>0x601058 | var2.var1.b | ==> 0x601058

| | var2.a |==>0x601054 var2.a | ==> 0x601054

in 64-bit machines int allocates 4-bytes & long allocates 8-bytes. 在64位机器中,int分配4个字节,长分配8个字节。

|var2.var1.b|==>0x601058 | var2.var1.b | ==> 0x601058

| | var2.a |==>0x601050 var2.a | ==> 0x601050

Memory alignment of structure members is explained here Alignment in c 结构成员的存储器对准这里说明对准在C

To figure out how the nested structure is stored in memory, you can run the code below: 要弄清楚嵌套结构如何存储在内存中,您可以运行以下代码:

#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;
}

I'm asking you to run this code on your implementation, rather than giving you an direct answer, because: 我要求你在你的实现上运行这段代码,而不是给你一个直接的答案,因为:

  1. sizeof T is implementation-define. sizeof T是implementation-define。 What if you have sizeof (long) == 1 and CHAR_BIT == 32 ? 如果你有sizeof (long) == 1CHAR_BIT == 32怎么办?
  2. There might be padding bits/bytes in a struct. 结构中可能有填充位/字节。
  3. Other factors. 其他因素。 For example, the use of #pragma pack(n) 例如,使用#pragma pack(n)

On my implementation (clang under OS X), the output is: 在我的实现(在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

Well, it does not seem neat here, but it's nicely-formatted when showing up on my screen. 好吧,它在这里看起来并不整洁,但是当我在屏幕上显示时,它的格式很好。

So (for my implementation) the memory layout of struct tag1 will be like this: 所以(对于我的实现) struct tag1的内存布局将是这样的:

 -----------------------
|  |  |  |  |  |  |  |  | ---> int a (8 bytes are used)
 -----------------------
|  |  |  |  |  |  |  |  | ---> struct tag2 / long b (8 bytes are used)
 -----------------------

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM