-2
#include<stdio.h>
struct krishna {
        int i,j,k,l,m;
    char c;
    double d;
    char g[48];
};
int main() {
struct krishna *me={0};
printf("%ld %ld\n",sizeof(me),sizeof(*me));//output is 8 80 how??
return 0;
}

大家好,我是新来的,我使用的编译器是上面代码中的 gcc 编译器,谁能解释一下原因

1)无论任何类型的指针都分配了 8 ?

2) 上述结构的大小为 80 ?任何人都可以向我解释任何结构的一般情况如何确定结构大小,每次我期望一个值但得到不同的答案时,我都会感到困惑,而且我还阅读了堆栈溢出中关于此的其他问题和答案,我是仍然没有得到它。请帮助。

4

4 回答 4

3

这是因为:

sizeof( me ) // is a pointer.

...me是一个指针。指针的大小是环境中单词的倍数,因此通常在 32 位环境中,指针为 4 字节,而在 64 位环境中,指针为 8 字节(但不是一成不变的)。如果你回到几年前,16 位环境将有一个 2 字节的指针。看下一个sizeof

sizeof( *me ) // is a struct krishna, hence 80 bytes are needed to store it in memory.

... 是一个结构,结构的大小krishna是 80 字节。如果你看结构:

struct krishna {
  int i,j,k,l,m; // sizeof( int ) * 5
  char c; // sizeof( char ) * 1
  double d; // sizeof( double ) * 1
  char g[48]; // sizeof( char ) * 48
  // padding for memory address offset would be here.
};

...如果您将每个字段所需的字节数相加,并为内存地址偏移量包括适当的数据结构对齐方式,那么它将总共 80 个字节(如预期的那样)。它添加额外 3 个未使用字节的原因是因为要将结构存储在内存中,它必须位于为该结构分配的连续内存块中。出于性能原因,它将填充任何大小问题以确保内存地址始终是字的倍数。用 3 个字节换取性能改进是值得的,现在 3 个字节的影响不如处理器在保证数据对齐的情况下的性能改进。

于 2013-08-14T18:22:07.730 回答
3

所有的指针都是地址,并且在给定的系统上所有地址的大小都相同,通常在 32 位系统上为 4 个字节,在 64 位系统上为 8 个字节。由于您获得 8,因此您必须使用 64 位系统。

结构的大小取决于编译器如何将结构的各个字段“打包”到单个内存块中以包含整个结构。在您的情况下,您的结构有 5 个 int 字段(每个 4 个字节)、一个 char 字段(1 个字节)、一个 double 字段(8 个字节)和一个 48 个字符的数组。将所有这些加起来,您将获得 20 + 1 + 8 + 48 = 77 个字节来存储您的数据。实际大小为 80,因为编译器使用 3 个额外未使用的字节“填充” 1 字节 char 字段,以使结构中的所有字段与 4 字节内存地址对齐,这是良好性能所必需的。

希望有帮助!

于 2013-08-14T18:24:55.443 回答
3
printf("%ld %ld\n",sizeof(me),sizeof(*me));//output is 8 80 how??

其实应该是:

printf("%zu %zu\n",sizeof(me),sizeof(*me));//output is 8 80 how??

"%zu"size_t值的正确格式字符串,例如您从sizeof. "%ld"可能碰巧在某些系统上工作(显然它在你的系统上),但你不应该指望这一点。

如果您的编译器不支持"%zu",您可以使用"%lu"(需要一个unsigned long参数)并显式转换参数:

printf("%lu %lu\n", (unsigned long)sizeof(me), (unsigned long)sizeof(*me));

你得到8sizeof(me)因为这恰好是你正在使用的编译器上的指针大小(8 字节,64 位)。如果您在不同的系统上编译并运行您的程序,您可能会得到4,因为很多系统都有 32 位指针。(这假设一个字节是 8 位,这对于大多数系统都是正确的,但语言不能保证。)

大多数编译器使所有指针大小相同,但这也不是由语言保证的。例如,在字寻址的机器上,int*指针可能只是一个机器级地址,但char*指针可能需要额外的信息来指定它指向的字中的哪个字节。您不太可能遇到指针大小不同的系统,但假设所有指针大小相同仍然没有意义。

至于结构的大小,也可能因编译器而异。这是你的结构:

struct krishna {
    int i,j,k,l,m;
    char c;
    double d;
    char g[48];
};

char总是正好是 1 个字节,并且char[48]总是正好是 48 个字节。

an 中的字节数int可能因系统而异;如今,4 个字节是最常见的。

a 的大小double通常为 8 字节,但这也可能有所不同(尽管我认为我从未见过sizeof (double)不是 8 字节的系统。)

结构成员按声明它们的顺序排列,因此您的iwill 位于结构的最开始,然后是j, k,依此类推。

最后,编译器通常会在成员之间或最后一个成员之后插入填充字节,以便每个成员正确对齐。例如,在许多系统上,一个 4 字节int需要在一个 4 字节的倍数的偏移处对齐;如果它未对齐,访问它可能会很慢和/或非常困难。

在您的系统上sizeof (struct krishna)恰好是 80 字节的事实并不是那么重要。更重要的是理解 (a) 编译器用来确定结构布局方式的一般规则,以及 (b) 这些规则可能导致不同系统的不同布局这一事实。

语言定义和您的编译器保证您可以拥有 type 的对象struct krishna,并且您可以访问这些对象及其成员,并取回您存储在其中的任何值。如果你想知道 a 有多大struct krishna,答案很简单sizeof (struct krishna)。如果由于某种原因,您需要了解更多细节(例如,如果您需要匹配一些外部强加的布局),您可以做一些实验和/或查阅编译器的文档——但请注意具体情况将适用仅适用于您在使用它的系统上使用的编译器。(通常,您系统的ABI会限制编译器的选择。)

您还可以使用sizeofand offsetof(查找)来找出每个成员的分配位置。

于 2013-08-14T18:54:12.790 回答
0

只是为了添加@Jacob Pollack 和@ObjetDart 的答案,您可以在Structure padding in C找到更多关于结构填充的信息。

于 2013-08-14T18:32:19.243 回答