在结构中填充

Ton*_*ony 7 c struct

我知道结构中填充(来自这篇文章的例子)

 struct A   -->8 bytes
 {
    char c;
    char d;
 //2 padding here
    int i;
 };
 struct B  -->12 bytes
 {
     char c;
 //3 padding here
    int i;
    char d;
 //3 padding here
 };
Run Code Online (Sandbox Code Playgroud)

现在,我不明白以下示例:

 typedef struct {  -->**shouldn't it be 12 bytes**
    int a;
    char *str;
 } TestS;

 TestS s;

int main(int argc, char *argv[]) {

   printf("An int is %lu bytes\n", sizeof( int )); -->4
   printf("A Char * is %lu bytes\n", sizeof( char *)); -->8
   printf("A double is %lu bytes\n", sizeof( double )); -->8

   printf("A struct is %lu bytes\n", sizeof s); -->why 16?

   return 0;

 }
Run Code Online (Sandbox Code Playgroud)

首先我认为它可能与8*N字节对齐(因为我使用的是ubuntu-64),所以我尝试了更多的结构.

  typedef struct {
   int i;
   char *str;
  } stru_12;


  typedef struct {
    int i;
    char *str;
    char c;
  } stru_13;

 typedef struct {
    int i;
    char str[7];
 } stru_11;

 typedef struct {
   char *str;
   double d;
 } stru_16;

  stru_12 test12;
  stru_13 test13;
  stru_11 test11;
  stru_16 test16;

int main (int argc, char *argv[]) {
    printf("A test12 is %lu bytes, address is %p\n", sizeof test12, &test12);
    printf("A test13 is %lu bytes, address is %p\n", sizeof test13, &test13);
    printf("A test11 is %lu bytes, address is %p\n", sizeof test11, &test11);
    printf("A test16 is %lu bytes, address is %p\n", sizeof test16, &test16);
}
Run Code Online (Sandbox Code Playgroud)

结果:

test12是16字节,地址是0x601060

test13是24字节,地址是0x601090

test11是12个字节,地址是0x601080

test16是16字节,地址是0x601070

很抱歉这么久.

我的问题是:

  • 为什么test12(int + char*)是16个字节而test13(int + char*+ char)是24?(似乎8*N是有利的,但允许12个字节)

  • 为什么结构地址的差异是16个寻址单元(更多填充?)?

供您使用:

cache_alignment:64

地址大小:36位物理,48位虚拟

Ubuntu 14.04.1 LTS x86_64

Who*_*aig 4

第二个问题是实现定义的(实际上,第一个问题也是如此,但我将向您展示为什么您无论如何都会获得间距)。您的平台显然是 64 位,因此您的数据指针同样是(64 位)。这样,我们就可以看到这些结构。


stru_12

typedef struct 
{
   int i;
   char *str;
} stru_12;
Run Code Online (Sandbox Code Playgroud)

这是对齐的,因此str总是落在 8 字节边界上,包括连续序列(数组)。为此,在i和之间引入了 4 个字节的填充str

0x0000 i    - length=4
0x0004 pad  - length=4
0x0008 ptr  - length=8
======================
Total               16
Run Code Online (Sandbox Code Playgroud)

这些数组将始终位于ptr8 字节边界上,前提是该数组以 said-same 开始(它会如此)。i由于在和之间添加填充str也使结构大小达到 8 的倍数,因此除此之外不需要额外的填充。


stru_13

现在,考虑一下如何实现这一点:

typedef struct 
{
    int i;
    char *str;
    char c;
} stru_13;
Run Code Online (Sandbox Code Playgroud)

相同的填充将再次应用于8 字节边界上的位置之间,但 的添加使i事情变得复杂。为了实现指针始终驻留在 8 字节边界(包括这些结构的序列/数组)的目标,该结构需要尾部填充,但是多少呢?好吧,我希望很明显整体结构大小需要是 8 的倍数,以确保任何嵌入的指针(也是 8 的倍数)正确对齐。在本例中,添加了 7 个字节的尾部填充以使大小达到 24 个字节:strstrc

0x0000 i    - length=4
0x0004 pad  - length=4
0x0008 ptr  - length=8
0x0010 c    - length=1
0x0011 pad  - length=7
======================
Total               24
Run Code Online (Sandbox Code Playgroud)

stru_13(双人部分)

所以试试这个。您可能会认为我们之前拥有的相同字段但顺序不同,会产生什么结果:

typedef struct 
{
    char *str;
    int i;
    char c;
} stru_13;
Run Code Online (Sandbox Code Playgroud)

好吧,我们知道我们想要str8 字节边界和i4 字节边界,坦率地说,我们根本不在乎c(总是伴娘):

0x0000 ptr  - length=8
0x0008 i    - length=4
0x000c c    - length=1
0x000d pad  - length=3
======================
Total               16
Run Code Online (Sandbox Code Playgroud)

通过您的测试程序运行它,您将看到它的结果如我们上面所示。它减少到 16 字节。我们所做的只是将顺序更改为仍然支持我们的要求的空间友好的布局,并且我们将默认表示减少了 8 个字节(先前布局的原始结构的三分之一)。如果说这是从这一切中剔除的一件重要的事情,那是轻描淡写的。

  • @martin `stru_11` 没有指针或双精度数,因此 8 字节边界超出了门外,但对地址 `i` (32 位 `int`)的理想访问应该将其放在 4 字节边界上,并且再次保持按顺序排列。为了实现这一点,在结构尾部添加了一个额外的填充。结果是 12 字节长度,而 `i` 总是落在 4 字节边界上(当然,假设它从 1 开始,确实如此)。尝试将“long”和“short”替换为“i”的类型,看看会发生什么。 (2认同)