【问题标题】:ctypes cdecl gives 4 bytes missing when calling gcc compiled dll returning a structctypes cdecl 在调用 gcc 编译的 dll 返回结构时缺少 4 个字节
【发布时间】:2012-06-09 01:45:51
【问题描述】:

我有一个想要使用 ctypes 调用的 c 库 (chipmunk)。但是,它在返回结构的函数上失败?

我得到的错误是

File "qw.py", line 19, in <module>
b = cpBBNew3(1,2,3,4)
ValueError: Procedure called with not enough arguments (4 bytes missing) or wrong calling convention

这是(相关的)c 代码: 在 cpBB.h

typedef struct cpBB {
    cpFloat l, b, r ,t;
} cpBB;
cpBB cpBBNew3(cpFloat l, cpFloat b, cpFloat r, cpFloat t);

在 cpBB.c 中

cpBB cpBBNew3(cpFloat l, cpFloat b, cpFloat r, cpFloat t) {
    cpBB bb = {l, b, r, t};
    return bb;
}

编译

gcc -O3 -std=gnu99 -shared -c

gcc -O3 -std=gnu99 -shared -s

那么python看起来像

from ctypes import *

chipmunk_lib = cdll.LoadLibrary('''C:/code/pymunk/trunk/pymunk/chipmunk.dll''')

class cpBB(Structure):
    pass
cpBB._pack_ = 4
cpBB._fields_ = [
    ('l', c_double),
    ('b', c_double),
    ('r', c_double),
    ('t', c_double),
]

cpBBNew3 = chipmunk_lib.cpBBNew3
cpBBNew3.restype = cpBB
cpBBNew3.argtypes = [c_double, c_double, c_double, c_double]

b = cpBBNew3(1,2,3,4)

如果我使用 -mrtd 编译并使用 windll(使用 stdcall),则此特定示例有效。然而,当使用优化和新版本的 GCC 编译时,在整个库上使用 stdcall 会在库的其他部分产生分段错误,这就是让 cdecl 正常工作的原因。

【问题讨论】:

  • 请注意,如果使用 stdcall 和优化导致分段错误,那么您的代码中可能存在使用 cdecl 进行屏蔽的错误。
  • @HarryJohnston 我在这里问了这个错误:stackoverflow.com/questions/10902348/… 从duskwuff 的回答看来我不应该使用stdcall,意思是cdecl 必须是要走的路?
  • 您必须使用该函数预期的调用约定来调用外部函数,因此如果您需要相同的函数指针能够指向外部(C 库)函数或内部(您的code) 函数,那么,是的,你必须坚持使用 cdecl。
  • (如果找不到更好的解决方案,一种解决方法是更改​​ cpBBNew3,使其将指向结构的指针作为参数之一并返回 void。)

标签: python windows gcc ctypes


【解决方案1】:

根据结构的大小和编译器/平台,cdecl 可以通过在普通参数之前将隐藏指针传递给调用者分配的结构来返回结构。请尝试以下操作:

b = cpBB()
cpBBNew3(byref(b),1,2,3,4)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-10-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-28
    • 2018-10-28
    • 2019-05-16
    相关资源
    最近更新 更多