struct struct_a { int x; 浮动; char a; dou ...

问题描述 投票:0回答:0

#include <stdio.h> #include <stddef.h> struct struct_a { int x; float y; char a; double z; }; int main(void) { printf("sizeof struct %zu\n", sizeof(struct struct_a)); printf("Offset of x: %lu\n", offsetof(struct struct_a, x)); printf("Offset of y: %lu\n", offsetof(struct struct_a, y)); printf("Offset of a: %lu\n", offsetof(struct struct_a, a)); printf("Offset of z: %lu\n", offsetof(struct struct_a, z)); return 0; }

观察输出:

为64位组合(默认或
-m64
选项):

sizeof struct 24 Offset of x: 0 Offset of y: 4 Offset of a: 8 Offset of z: 16

padding的7个字节
在偏移16

处对齐
a
(8的倍数)。
    总结构尺寸为
  • 24字节,确保了适当的数组对齐。 32位的组合(
    z
    选项):
    
    -m32
    
  • 3padding的3个字节在偏移时对齐
  • sizeof struct 20 Offset of x: 0 Offset of y: 4 Offset of a: 8 Offset of z: 12

总结构大小为20字节

,它是8个倍数,而结构元素可能并不总是在数组中自然对齐。

问题:

    thy是为什么在32位版本中放置在偏移量12时,当时是8字节类型的?
  • I期望a
    z
    将与
    8字节边界对齐,但是在32位模式下,它是在12上对齐的。我了解一个32位系统在每个周期中处理
  • 4字节块
  • 的数据 - 这会影响double的一致性。

我应该如何在工作面试中解释结构填充?

    compiner的行为可能会在平台之间有所不同,当被问及结构对齐和填充时,构架答案的最佳方法是什么?我是否应该专注于一般规则(例如与最大类型保持一致),或解释对齐方式可以根据体系结构和编译器的优化而有所不同吗?
  1. 我已经检查了以下堆栈溢出讨论,但是它们似乎更复杂,因为我试图从初学者中理解。

    带有UINT64_T

      的32位和64位体系结构中的结构填充差 32位和64位体系结构中的结构成员对齐中的调查
    • 
      
      Edit:
      I编译了-M32和-M64输出,并在我的Ubuntu System上进行了一些代码更改。
      double
      
      gdb的记忆布局-M32编译二进制
      
      double
  2. IT似乎基于4个字节的结构字段对齐,并且是否根据其大小的多个对齐结构字段并不重要。
  3. i我试图将一个宣布为2个元素的数组,并且没有严格的数据对齐其倍数。 // use the same struct_a form the above code, a.x = 0xFFFFFF; // 2 nibble should show 0x00 and rest all 0xff a.c = 'A'; *(uint32_t *)&a.y = 0xFFFFFFFF; // Force 0xff bytes for float *(uint64_t *)&a.z = 0xFFFFFFFFFFFFFFFF; // Force 0xff bytes for double

    gdb的记忆布局-M64编译二进制
      $1 = {x = 16777215, y = -nan(0x7fffff), c = 65 'A', z = -nan(0xfffffffffffff)} (gdb) x/20bx &a 0x56559008 <a>: 0xff 0xff 0xff 0x00 0xff 0xff 0xff 0xff 0x56559010 <a+8>: 0x41 0x00 0x00 0x00 0xff 0xff 0xff 0xff 0x56559018 <a+16>: 0xff 0xff 0xff 0xff // 0x56559008 x, 0x56559008 y, 0x56559010 a, < 3 byte padding >, 0x56559010 z. (gdb) p &a.x $6 = (int *) 0x56559008 <a> (gdb) p &a.y $7 = (float *) 0x5655900c <a+4> (gdb) p &a.c $8 = 0x56559010 <a+8> "A" (gdb) p &a.z $9 = (double *) 0x56559014 <a+12>
    对准基于8个字节,即使64位,地址是否为8个字节也无关紧要。
因此,我尝试通过声明[2]并分配相同的初始化值来执行数组相同的执行。

(gdb) x/40bx &a 0x56559040 <a>: 0xff 0xff 0xff 0x00 0xff 0xff 0xff 0xff 0x56559048 <a+8>: 0x41 0x00 0x00 0x00 0xff 0xff 0xff 0xff 0x56559050 <a+16>: 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0x00 0x56559058 <a+24>: 0xff 0xff 0xff 0xff 0x41 0x00 0x00 0x00 0x56559060 <a+32>: 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff (gdb) p &a[0].z $2 = (double *) 0x5655904c <a+12> (gdb) p &a[1].x $3 = (int *) 0x56559054 <a+20>

末端开始
对于

a[1].x

开始,从数组元素1的开始开始,地址从0x5555555558058开始,这不是8个倍数。


为什么在32位版本中以8字节类型的方式放置在Offset 12中?

因为它是这样指定的。
    文件i386 abi指定对the the的对齐thttps://www.uclibc.org/docs/psabi-i386.pdf
  • 文档在第8页的表22.1中。 .
但文档X86-64 ABI根据此

Https://refspecs.linuxbase.org/elf/x86_64-abi-0.99.pdf

文件表3.1第12.1页上的第12页。
编译器根据规范创建结构。所有编译器都使用相同的规格,因此生成的代码可以相互交谈。
这会影响双重对齐吗?

也许是在i386的理由中。读取与两个双打的结构对齐是4,即使双重对齐为8(32bit)
最好在8上对齐双打。但是ABI是IT。
    
c gcc struct
最新问题
© www.soinside.com 2019 - 2025. All rights reserved.