为什么sizeof在ctypes struct packing的给定示例中有所不同?

时间:2017-03-01 17:15:31

标签: python c struct padding ctypes

如果能够对下面一段代码的输出进行任何解释,我将非常感激。我不明白为什么sizeof(struct_2)sizeof(my_struct_2)不同,提供 sizeof(struct_1)sizeof(c_int) 相同

似乎ctypesstruct内以某种不同的方式打包struct

from ctypes import *

class struct_1(Structure):
    pass
int8_t = c_int8
int16_t = c_int16
uint8_t = c_uint8
struct_1._fields_ = [
    ('tt1', int16_t),
    ('tt2', uint8_t),
    ('tt3', uint8_t),
]

class struct_2(Structure):
    pass
int8_t = c_int8
int16_t = c_int16
uint8_t = c_uint8
struct_2._fields_ = [
    ('t1', int8_t),
    ('t2', uint8_t),
    ('t3', uint8_t),
    ('t4', uint8_t),
    ('t5', int16_t),
    ('t6', struct_1),
    ('t7', struct_1 * 6),
]

class my_struct_2(Structure):
    #_pack_ = 1  # This will give answer as 34
    #_pack_ = 4  #36
    _fields_ = [
    ('t1', c_int8),
    ('t2', c_uint8),
    ('t3', c_uint8),
    ('t4', c_uint8),
    ('t5', c_int16),
    ('t6', c_int),
    ('t7', c_int * 6),
]

print "size of c_int            : ", sizeof(c_int)
print "size of struct_1         : ", sizeof(struct_1)
print "size of my struct_2      : ", sizeof(my_struct_2)
print "siz of origional struct_2: ", sizeof(struct_2)

输出:

size of c_int            :  4
size of struct_1         :  4
size of my struct_2      :  36  
siz of origional struct_2:  34 ==> why not 36 ??

修改 重命名t6-> t7(struct_1数组)并从struct_2中删除 pack = 2。但我仍然看到struct_2my_struct_2

的大小不同

1 个答案:

答案 0 :(得分:0)

差异源于结构布局中元素之间或之后是否存在填充,因为当大小不同时,较大的元素占所有单个结构成员所需的字节数。只有成员t5t6足以证明其差异,如果省略t5(仅限),则没有区别。

一些实验表明,默认情况下(即未指定_pack_成员时),ctypes为结构类型struct_1提供2字节对齐,但为类型{{1提供4字节对齐}}。或者它在我的系统上,无论如何。 ctypes文档声称默认情况下它以与系统的C编译器(默认情况下)相同的方式布局结构,而事实上似乎就是这种情况。考虑一下这个C程序:

c_int

我的输出(在x86_64上的CentOS 7 w / GCC 4.8上)是:

The size of int is       4
The size of struct s  is 4
The size of struct t1 is 6
The size of struct t2 is 8

The offset of t1.y is    2
The offset of t2.y is    4

注意#include <stdio.h> #include <stdint.h> #include <stddef.h> int main() { struct s { int16_t x; int8_t y; uint8_t z; }; struct t1 { int16_t x; struct s y; }; struct t2 { int16_t x; int y; }; printf("The size of int is %zu\n", sizeof(int)); printf("The size of struct s is %zu\n", sizeof(struct s)); printf("The size of struct t1 is %zu\n", sizeof(struct t1)); printf("The size of struct t2 is %zu\n", sizeof(struct t2)); printf("\nThe offset of t1.y is %zu\n", offsetof(struct t1, y)); printf("The offset of t2.y is %zu\n", offsetof(struct t2, y)); } int的大小相同(4个字节),但编译器在struct s内的2字节边界上对齐struct s ,它将struct t1int内的4字节边界对齐。这与同一系统上的ctypes行为完全匹配。

至于为什么 GCC选择它做的对齐,我观察到如果我将struct t2类型的成员添加到int,那么GCC会切换到使用4字节对齐对于结构,以及安排(默认情况下)结构中struct s的偏移量为4个字节的倍数。可以合理地得出结论,GCC在结构中布置成员并选择整体结构的对齐,以便每个对齐的结构实例的所有成员本身自然对齐。但请注意,这只是一个例子。在选择结构布局和对齐要求方面,C实现主要由他们自行决定。