2

我有一个这样的 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,

约翰

4

1 回答 1

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

因此,您的“最小值”值为 3,而您的“最大值”值为 0。

您还可能通过传递一些代码认为是 128 位而其他代码认为它是 64 位的东西来最终分割对象和/或覆盖内存。例如,如果您创建一个 my_domain_int32_range_t,将其通过引用传递给 Python,然后尝试设置其“最大值”值,那么您将设置一个只有 2 个对象的第 3 位和第 4 位 32 位,这意味着您re 实际上覆盖了内存中的下一个对象。

上面的详细信息假设您使用的是小端系统(如 x86_64),而不是大端系统或不同的系统(是否有任何 VAX 端 LP64 平台?使用 Python?)。在具有 Python 的 64 位 big-endian PowerPC 构建的 PowerMac G5 上,您将得到 (0, 3) 而不是 (3, 0)。但基本思想是一样的。

于 2012-06-19T23:43:31.333 回答