我有一个像这样的C结构:
typedef struct {
my_domain_type_t type;
my_domain_union_t u;
my_domain_int32_list_t list;
} my_domain_value_t;
typedef struct {
int32_t min;
int32_t max;
} my_domain_int32_range_t;
我想从ctypes调用的C函数:
int64_t myData::get_min(const my_domain_value_t &value)
{
int min_value = 0;
my_domain_type_t dt = value.type;
if (dt == 0)
{
my_domain_int32_range_t range = value.u.range;
min_value = range.min;
printf("min_value=%d\n", min_value);
}
return min_value;
}
ctypes定义:
class myDomainInt32RangeT(Structure):
_fields_ = [ ('min', c_long),
('max', c_long) ]
class myDomainUnionT(Union):
_fields_ = [ ('range', myDomainInt32RangeT ) ]
class myDomainValueT(Structure):
_fields_ = [ ('type', c_int ),
('u', myDomainUnionT ),
('list', myDomainInt32ListT ) ]
class myData(object):
def __init__(self):
self.object = myDataX.myData_new()
def get_min(self, arg1):
myDataX.myData_get_min.argtypes = [ c_void_p, POINTER(myDomainValueT) ]
myDataX.myData_get_min.restype = c_longlong
return myDataX.mydata_get_min(self.object, arg1)
Python代码:
mydataY = myData()
domainRange = myDomainInt32RangeT()
domainRange.min = c_long(3)
domainRange.max = c_long(5)
domainUnion = myDomainUnionT()
domainUnion.range = domainRange
domainValue = myDomainValueT()
domainValue.type = 0
domainValue.u = domainUnion
domainValue.list = myDomainInt32ListT()
b = mydataY.get_min( byref(domainValue) )
print(b)
我期望min_value的值为3,但我一直得到0. C代码也打印0.看起来联合没有正确设置/传输。
我做错了什么?。
TIA,
约翰
答案 0 :(得分:2)
如果希望myDomainInt32RangeT结构与my_domain_int32_range_t结构互换使用,则必须定义兼容类型。但他们没有:
typedef struct {
int32_t min;
int32_t max;
} my_domain_int32_range_t;
这定义了一对int32_t值。
class myDomainInt32RangeT(Structure):
_fields_ = [ ('min', c_long),
('max', c_long) ]
这定义了一对长值。
问题是int32_t和long不是同一类型。修复很简单:更改一个以匹配另一个(例如,使用c_int32而不是c_long)。
如果你想了解为什么得到0,那就更多了。
int32_t的规则说它必须是32位。长期规则说它必须至少为32位。在大多数32位平台上,在64位Windows上,它只有32位。但是,在大多数其他64位平台上,它是64位。 (有关详细信息,请参阅http://en.wikipedia.org/wiki/64-bit处有关LLP64与LP64的讨论。)
您可能使用的是64位Intel Mac或Linux系统,并使用默认的Python。因此,你的long,因此ctypes.c_long是64位整数。那么,看一下myDomainInt32RangeT的布局:
1st 32 bits: low half of the 64-bit "min" value
2nd 32 bits: high half of the 64-bit "min" value
3rd 32 bits: low half of the 64-bit "max" value
4th 32 bits: high half of the 64-bit "max" value
相比之下,my_domain_int32_range_t的布局如下:
1st 32 bits: 32-bit "min" value
2nd 32 bits: 32-bit "max" value
因此,如果您构建myDomainInt32RangeT(3,5),那么您要创建的是:
1st 32 bits: 3 (low half of 64-bit 3)
2nd 32 bits: 0 (high half of 64-bit 3)
3rd 32 bits: 5 (low half of 64-bit 5)
4th 32 bits: 0 (high half of 64-bit 5)
当您尝试将其解释为my_domain_int32_range_t时,它会看到:
1st 32 bits: 3
2nd 32 bits: 0
所以你的“min”值是3,你的“max”值是0。
你也可能最终通过传递一些代码认为是128位的东西来切片对象和/或覆盖内存,而其他代码认为它是64位。例如,如果你创建一个my_domain_int32_range_t,通过引用将它传递给Python,然后尝试设置它的“max”值,你设置一个对象的第3和第4位只有2个,这意味着你'实际上覆盖了内存中的下一个对象。
上面的细节假设您使用的是小端系统(如x86_64),而不是大端系统或其他不同的东西(有没有任何VAX-endian LP64平台?使用Python?)。在具有64位big-endian PowerPC版本的Python的PowerMac G5上,你将获得(0,3)而不是(3,0)。但基本思路是一样的。