我如何计算结构成员和填充的大小?

时间:2017-09-02 02:11:35

标签: c struct padding

假设我有一个结构:

struct simple_struct_1
{
  long long a;
  char b;
  long c;
};

a的地址是:0x7ffd415c8b20 b的地址是:0x7ffd415c8b28 c的地址是:0x7ffd415c8b30 simple_struct_1的尺寸为24

我已经打印了每个成员的地址和结构的大小,我如何展示这个结构在内存中的规定?就像在simple_struct_1中一样,a占用111个字节并且有222个填充字节,之后b占用333个字节,其后有0个填充字节,c占用444个字节它后面有555个字节的填充。

3 个答案:

答案 0 :(得分:4)

您可以使用offsetofsizeof获取每个字段的详细信息以及整个结构的大小,例如:

printf ("a      is %d@%d\n", sizeof(simple_struct_1.a), offsetof(simple_struct_1, a));
printf ("b      is %d@%d\n", sizeof(simple_struct_1.b), offsetof(simple_struct_1, b));
printf ("c      is %d@%d\n", sizeof(simple_struct_1.c), offsetof(simple_struct_1, c));
printf ("struct is %d@0\n",  sizeof(simple_struct_1));

这应该让你能够解决:

  • 所有字段的偏移量和大小;
  • 字段之间的间隙;和
  • 最后一个字段后的间隙(将其偏移量和大小与整个结构的大小相结合。

不要担心在第一个字段之前填充,ISO标准禁止这样做。

例如,假设您在左侧看到以下输出,尺寸和间隙显示在右侧:

a      is 16@0        16 bytes for a long long
                      no gap (0 + 16 = 16, next at 16)
b      is 1@16         1 byte  for a char
                       7 bytes gap (16 + 1 = 17, next at 24)
c      is 8@24         8 bytes for a long
struct is 32@0        no gap at end (24 + 8 = 32, next at 32)

答案 1 :(得分:1)

您可以使用offsetof()宏来查找来自第一个成员的每个字段的偏移量(必须与struct具有相同的地址),因为在第一个成员之前不允许填充)。

使用struct运算符将此信息与各种成员的大小(以及整个sizeof的大小以查找尾随填充字节数)相结合,可以推断出填充字节是。这是一个打印出成员地址和偏移量的程序。它还打印成员字节和填充字节的图形表示;破折号表示填充字节。

#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>

struct simple_struct_1 {
    long long a;
    char b;
    long c;
};

char * graph_member(char *ptr, size_t member_sz, size_t padding_sz);

int main(void)
{
    struct simple_struct_1 my_struct;

    printf("sizeof (struct simple_struct_1) = %zu\n",
           sizeof (struct simple_struct_1));
    putchar('\n');

    void *ptra = &(my_struct.a);
    void *ptrb = &(my_struct.b);
    void *ptrc = &(my_struct.c);

    size_t offset_a = offsetof(struct simple_struct_1, a);
    size_t offset_b = offsetof(struct simple_struct_1, b);
    size_t offset_c = offsetof(struct simple_struct_1, c);

    /* Allocate memory for struct padding visualization */
    char *graph = malloc(sizeof my_struct + 1);

    if (graph == NULL) {
        perror("Virtual memory exhausted");
        exit(EXIT_FAILURE);
    }

    char *ptr = graph;

    printf("&(my_struct.a) = %p\n", ptra);
    printf("sizeof my_struct.a = %zu\n", sizeof my_struct.a);
    putchar('\n');
    ptr = graph_member(ptr,
                       sizeof my_struct.a,
                       offset_b - sizeof my_struct.a);

    printf("&(my_struct.b) = %p\n", ptrb);
    printf("sizeof my_struct.b = %zu\n", sizeof my_struct.b);
    printf("&(my_struct.b) - &(my_struct.a) = %zu\n", offset_b - offset_a);
    putchar('\n');
    ptr = graph_member(ptr,
                       sizeof my_struct.b,
                       offset_c - offset_b - sizeof my_struct.b);

    printf("&(my_struct.c) = %p\n", ptrc);
    printf("sizeof my_struct.c = %zu\n", sizeof my_struct.c);
    printf("&(my_struct.c) - &(my_struct.b) = %zu\n", offset_c - offset_b);
    putchar('\n');
    ptr = graph_member(ptr,
                       sizeof my_struct.c,
                       sizeof my_struct - offset_c - sizeof my_struct.c);

    /* Null-terminate graph string and display */
    ptr = '\0';
    puts(graph);

    free(graph);

    return 0;
}

char * graph_member(char *ptr, size_t member_sz, size_t padding_sz)
{
    /* Indicate member */
    for (size_t i = 0; i < member_sz; i++) {
        *ptr = '*';
        ++ptr;
    }

    /* Indicate padding */
    for (size_t i = 0; i < padding_sz; i++) {
        *ptr = '-';
        ++ptr;
    }

    return ptr;
}

示例程序输出:

sizeof (struct simple_struct_1) = 24

&(my_struct.a) = 0x7ffee4af4610
sizeof my_struct.a = 8

&(my_struct.b) = 0x7ffee4af4618
sizeof my_struct.b = 1
&(my_struct.b) - &(my_struct.a) = 8

&(my_struct.c) = 0x7ffee4af4620
sizeof my_struct.c = 8
&(my_struct.c) - &(my_struct.b) = 8

*********-------********

答案 2 :(得分:0)

你可以尝试使用pahole(poke -a -hole)。这将有助于您的需求。

这是对它的引用。 pahole