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 を出力します。ユニオンが正しくセットアップ/転送されないようです。

私は何を間違えましたか?

ティア、

ジョン

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) ]

これは、任意の long 値のペアを定義します。

問題は、int32_t と long が同じ型ではないことです。修正は簡単です。一方を他方に合わせて変更します (たとえば、c_long の代わりに c_int32 を使用します)。

0 になる理由を理解したい場合は、もう少し複雑です。

int32_t の規則では、32 ビットである必要があります。long のルールでは、少なくとも 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 ビットを設定していることになります。メモリ内の次のオブジェクトを実際に上書きします。

上記の詳細は、ビッグ エンディアン システムまたは別のもの (Python を使用する VAX エンディアン LP64 プラットフォームはありますか?) とは対照的に、リトル エンディアン システム (x86_64 など) を使用していることを前提としています。Python の 64 ビット ビッグ エンディアン PowerPC ビルドを搭載した PowerMac G5 では、(3, 0) ではなく (0, 3) を取得します。しかし、基本的な考え方は同じです。

于 2012-06-19T23:43:31.333 に答える