20

当我只运行代码片段时

int *t;
std::cout << sizeof(char)   << std::endl;
std::cout << sizeof(double) << std::endl;
std::cout << sizeof(int)    << std::endl;
std::cout << sizeof(t)      << std::endl;

它给了我这样的结果:

1
8
4
4

总数:17。

但是当我测试包含这些数据类型的 sizeof 结构时,它给了我 24,我很困惑。额外的 7 个字节是什么?

这是代码

#include <iostream>
#include <stdio.h>
struct struct_type{
    int i;
    char ch;
    int *p;
    double d;
} s;

int main(){
    int *t;
    //std::cout << sizeof(char)   <<std::endl;
    //std::cout << sizeof(double) <<std::endl;
    //std::cout << sizeof(int)    <<std::endl;
    //std::cout << sizeof(t)      <<std::endl;

    printf("s_type is %d byes long",sizeof(struct struct_type));

    return 0;
}

:编辑

我已经像这样更新了我的代码

#include <iostream>
#include <stdio.h>
struct struct_type{
    double d_attribute;
    int i__attribute__(int(packed));
    int * p__attribute_(int(packed));;
    char  ch;
} s;

int main(){
    int *t;
    //std::cout<<sizeof(char)<<std::endl;
    //std::cout<<sizeof(double)<<std::endl;
    //std::cout<<sizeof(int)<<std::endl;
    //std::cout<<sizeof(t)<<std::endl;

    printf("s_type is %d bytes long",sizeof(s));

    return 0;
}

现在它显示了 16 个字节。好不好,还是我丢失了一些重要的字节?

4

9 回答 9

52

一些成员之间有一些未使用的字节以保持对齐正确。例如,为了效率,一个指针默认驻留在 4 字节边界上,即它的地址必须是 4 的倍数。如果结构只包含一个 char 和一个指针

struct {
  char a;
  void* b;
};

然后b不能使用 adderss #1 — 它必须放在 #4。

  0   1   2   3   4   5   6   7
+---+- - - - - -+---------------+
| a | (unused)  | b             |
+---+- - - - - -+---------------+

在您的情况下,额外的 7 个字节来自 3 个字节(由于 对齐int*)和 4 个字节(由于double.

  0   1   2   3   4   5   6   7   8   9   a   b   c   d   e   f
+---------------+---+- - - - - -+---------------+- - - - - - - -+
| i             |ch |           | p             |               |
+---------------+---+- - - - - -+---------------+- - - - - - - -+
 10  11  12  13  14  15  16  17
+-------------------------------+
| d                             |
+-------------------------------+
于 2010-08-15T09:39:45.547 回答
9

...它给了我 24,我很困惑。额外的 7 个字节是什么?

这些是编译器插入的填充字节。数据结构填充取决于实现。

来自维基百科,数据结构对齐

数据对齐意味着将数据放置在等于字大小的某个倍数的内存偏移处,由于 CPU 处理内存的方式,这会提高系统的性能。为了对齐数据,可能需要在最后一个数据结构的结尾和下一个数据结构的开头之间插入一些无意义的字节,这就是数据结构填充。

于 2010-08-15T09:37:08.733 回答
8

为了稍微扩展 KennyDM 的优秀答案(Kenny - 如果你愿意,请偷这个来补充你的答案),这可能是编译器对齐所有变量后你的内存结构的样子:

  0    1    2    3    4    5    6    7
+-------------------+----+-----------+
| i                 | ch | (unused)  |
+-------------------+----+-----------+

  8    9   10   11   12   13   14   15
+-------------------+----------------+
| p                 |   (unused)     |
+-------------------+----------------+

 16   17   18   19   20   21   22   23
+------------------------------------+
| d                                  |
+------------------------------------+

因此,由于“ch”和“p”之间的 3 字节间隙以及“p”和“d”之间的 4 字节间隙,您的结构得到了 7 字节的填充,因此大小为 24 字节。由于您的环境double具有 8 字节对齐(即,它必须驻留在它自己的 8 字节块中,如上所示),整个环境struct也将总体上是 8 字节对齐,因此甚至重新排序变量不会改变 24 字节的大小。

于 2010-08-15T09:58:27.230 回答
1

It's 24 bytes due to padding. Most compilers pad data to a multiple of its size. So, a 4-byte int is padded to a multiple of 4 bytes. A 8-byte double is padded to a multiple of 8 bytes. For your structure, this means:

struct struct_type{
  int i; // offset 0 (0*4)
  char ch; // offset 4 (4*1)
  char padding1[3];
  int *p; // offset 8 (2*4)
  char padding1[4];
  double d; // offset 16 (2*8)
}s;

You can optimize your struct like that:

struct struct_type{
  double d;
  int i;
  int *p;
  char ch;
}s;

sizeof(s)==17 on most compilers (20 on some others)

于 2010-08-15T09:48:03.467 回答
0

允许编译器将结构的成员与地址对齐,以便更快地访问。例如 32 位边界。只有标准要求对象的成员按照声明的顺序存储。因此,请始终确保您使用sizeof以及offsetof何时需要内存中的确切位置。

于 2010-08-15T09:39:59.130 回答
0

comp.lang.c 常见问题列表 · 问题 2.12

为什么我的编译器会在结构中留下漏洞、浪费空间并阻止“二进制”I/O 到外部数据文件?我可以关闭它,或者以其他方式控制结构字段的对齐方式吗?

于 2010-08-15T09:43:20.850 回答
0

额外的大小来自数据对齐,即成员对齐到 4 或 8 字节的倍数。

您的编译器可能将 int 和指向倍数的指针对齐 4 个字节,将双精度指向倍数的 8 个字节。

如果将 double 移动到结构中的不同位置,则可以将结构的大小从 24 字节减少到 20 字节。但这取决于编译器。

于 2010-08-15T09:44:49.353 回答
0

Also sometimes you need the struct to mantain the order you required. In this cases, if you are using gcc, you should use the __attribute__((packed)) statement.

See also this for further info.

于 2010-08-15T09:45:28.510 回答
0

$9.2/12 states - "Nonstatic data members of a (non-union) class declared without an intervening access-specifier are allocated so that later members have higher addresses within a class object. The order of allocation of nonstatic data members separated by an access-specifier is unspecified (11.1). Implementation alignment requirements might cause two adjacent members not to be allocated immediately after each other; so might requirements for space for managing virtual functions (10.3) and virtual base classes (10.1)."

So just like the sizeof(double) and sizeof(int), the offsets at which structure members would be aligned is unspecified, except that members that are declared later are at higher addresses.

于 2010-08-15T09:54:05.663 回答