如何通过python ctypes将二进制缓冲区传递给c函数

时间:2011-03-14 21:49:49

标签: python wrapper ctypes

我想在python 2.x中包装以下c函数bar()并调用 它通过ctypes模块,在Linux和Windows上:

#include <stdio.h>

#ifdef FOO_DLL
#define FOO_API __declspec(dllexport)
#else
#define FOO_API extern
#endif

FOO_API unsigned int bar(const void* data, unsigned int len) 
{
   printf("%p (%d bytes)\n", data, len);
   return len;
}

要编译共享库,我使用scons:

import sys

env = Environment()
if sys.platform == 'win32':
  env.Append(CFLAGS=['-DFOO_DLL'])

env.SharedLibrary('foo', ['foo.c'])

最后,我加载了相应的共享库并调用了函数:

import sys
import struct
from ctypes import *

if sys.platform == 'win32':
  libfoo = windll.LoadLibrary('foo')
else:
  libfoo = cdll.LoadLibrary('./libfoo.so')

data = struct.pack('BBB', 0, 1, 2)
libfoo.bar(data, len(data))

令我惊讶的是,这似乎在Linux下完美无缺,但在Windows上 代码抛出一个错误,让我怀疑这不是正确的 做事的方式:

$ python foo.py
00B520C4 (3 bytes)
Traceback (most recent call last):
  File "foo.py", line 11, in <module>
    libfoo.bar(data, len(data))
ValueError: Procedure probably called with too many arguments (8 bytes in excess)

什么是正确的方法?

在Linux(Ubuntu 10.10 64bit)上我使用的是Python 2.6.6,gcc 4.4.5和Windows(XP 32bit,在VirtualBox中)Python 2.7.1和VS2010 Express。

1 个答案:

答案 0 :(得分:1)

Windows和Linux都应使用cdll,从而产生C调用约定。目前,Python代码使用stdcall调用Windows DLL,但它实际上是cdecl函数。 cdllwindll之间的区别仅仅是使用的调用约定。

该错误消息是一个教科书调用约定不匹配错误,因为它的价值。