Python 为什么在给定的ctypes结构打包示例中sizeof会发生变化?
若能对以下代码的输出给出任何解释,我将不胜感激。我不明白为什么Python 为什么在给定的ctypes结构打包示例中sizeof会发生变化?,python,c,struct,padding,ctypes,Python,C,Struct,Padding,Ctypes,若能对以下代码的输出给出任何解释,我将不胜感激。我不明白为什么sizeof(struct_2)和sizeof(my_struct_2)是不同的,只要sizeof(struct_1)和sizeof(c_int)是相同的 似乎ctypes以某种不同的方式在struct中打包struct from ctypes import * class struct_1(Structure): pass int8_t = c_int8 int16_t = c_int16 uint8_t = c_uint
sizeof(struct_2)
和sizeof(my_struct_2)
是不同的,只要sizeof(struct_1)
和sizeof(c_int)
是相同的
似乎ctypes
以某种不同的方式在struct
中打包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(结构_1的数组)并从结构_2中删除pack=2。但是我仍然看到
struct_2
和my_struct_2
的大小不同,这是因为在结构布局中的元素之间或之后是否存在填充,因为当大小不同时,较大的元素所占的字节数大于所有单个结构成员所需的字节数。仅成员t5
和t6
就足以证明差异,如果省略t5
(仅限),则没有差异
一些实验表明,默认情况下(即未指定
\u pack\u
成员时),ctypes为结构类型struct\u 1
提供2字节对齐,但为类型c\u int
提供4字节对齐。或者在我的系统上也是这样。ctypes文档声称,默认情况下,它以与系统的C编译器(默认情况下)相同的方式布置结构,事实似乎确实如此。考虑这个C程序:
#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 main(){
结构{
int16_t x;
国际会议;
uint8_t z;
};
结构t1{
int16_t x;
结构y;
};
结构t2{
int16_t x;
int-y;
};
printf(“int的大小是%zu\n”,sizeof(int));
printf(“结构s的大小为%zu\n”,sizeof(结构s));
printf(“struct t1的大小为%zu\n”,sizeof(struct t1));
printf(“结构t2的大小为%zu\n”,sizeof(结构t2));
printf(“\n t1.y的偏移量为%zu\n”,偏移量为(结构t1,y));
printf(“t2.y的偏移量为%zu\n”,偏移量为(结构t2,y));
}
它对我的输出(在CentOS 7上,在x86_64上,带有GCC 4.8)是:
int的大小是4
结构s的大小是4
结构t1的大小是6
结构t2的大小是8
t1.y的偏移量是2
t2.y的偏移量是4
注意int
和struct s
的大小是相同的(4个字节),但是编译器在struct t1
的2字节边界上对齐struct s
,而在struct t2
的4字节边界上对齐int
。这与同一系统上ctypes的行为完全匹配
至于GCC选择对齐方式的原因,我注意到,如果我将类型为
int
的成员添加到struct s
中,那么GCC将切换到对结构使用4字节对齐方式,并(默认情况下)将结构中int
的偏移量安排为4字节的倍数。可以合理地得出这样的结论:GCC在一个结构中布局成员,并选择整个结构的对齐方式,以便每个对齐的结构实例的所有成员都自然对齐。但是,请注意,这只是一个示例。在选择结构布局和对齐要求方面,C实现在很大程度上由它们自己决定。这是什么语言?如果“C”使用了一些我不熟悉的扩展。在我看来像Python,而不是C。我想这是因为struct_2
是打包的,所以t5
之后没有填充。但是my_struct_2
没有打包,所以t5
和t6
之间有两个字节的填充,以使其与单词对齐。顺便问一下,为什么在struct_2
和my_struct_2
中有两个t6
成员?第二个不应该是t7
?添加了[python](删除[memory alignment]以腾出空间),因为问题是关于python的“ctypes”module.ctypes为结构类型struct_1>>提供2字节的对齐方式,如果我显式使用u pack_u4,即使我看到不同的大小。如果我们在C代码中使用对齐和打包,那么它会给出预期的大小struct t1{int16_t x;struct s y;}属性((打包,对齐(4));int的大小是4,struct s的大小是4,struct t1的大小是8,struct t2的大小是8,t1的偏移量。y是2,t2的偏移量。y是4,我们如何在python中获得与ctypes相同的行为?pack=4不起作用。@AmitSharma,您误解了\u pack\u
的含义。它设置最大对齐。通过将其设置为一个较小的数字,可以获得较少的填充,甚至没有填充,但不能通过将其设置为较大的数字来强制增加填充。但是,您可以通过添加一个您可以忽略的成员来手动填充结构。@AmitSharma,据我所知,ctypes没有用于指定最小对齐方式的内置机制(GCC的\uuuuu属性的作用是((对齐))
)。
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