python字符串转换c,Python-将字符串对象转换为ctypes(无符号字符*)

I want to use a DLL file with a function that has the following signature -

bool isValid = isImageValid((unsigned char *) buff, const __uint32& buffLen,

int imageW, int imageH, __uint32 requiredSize);

Now, buff has to result from a string I'm getting to the python wrapper that is equaivalent to

pyBuff = open(someimagefile, 'rb').read()

Since pyBuff is big (mostly), I don't want to allocate a new c uchar array and copy, but to make use of the original buffer. Basically, grab the char buffer of the pyBuff object and reference it as a ctypes (c_ubyte *).

The closest I came to it is:

buff = cast(pyBuff, POINTER(c_ubyte))

But I'm not sure this is the type I want. Anyway, the function gives me the following error

WindowsError: exception: access violation writing 0x00000000

Will be glad for any help..

Also - two short questions:

Is the following a right definition,given that in an existing C wrapper to this DLL (which I'm working with as a reference) the function that calls (also) this one has the signature: (const char * buff, const __uint32& buffLen)

byref(c_ulong(len(pyBuff))

What's the difference between CDLL and WinDLL, and which is the right one to use?

解决方案

If all you have is the Python string and you're sure isImageValid won't modify its contents, then you can just declare the buff argument as type c_char_p. The buffer contents won't be copied.

The _type_ code of c_char_p is 'z'. In the 2.5.4 source for the setter function, _ctypes/cfield.c : z_set, you see that for an str object it simply uses the underlying ob_sval pointer:

1309 if (PyString_Check(value)) {

1310 *(char **)ptr = PyString_AS_STRING(value);

1311 Py_INCREF(value);

1312 return value;

where the macro is defined as follows:

#define PyString_AS_STRING(op) (((PyStringObject *)(op))->ob_sval)

That said, if you can read the source file, you may prefer to read it into a mutable buffer. Here's how to read the contents into a ctypes c_char array (tested in 2.5.4):

Create a test file to be read:

>>> open('tmp.txt', 'w').write('''\

... This is a test.''')

Get the file size in a c_uint32, create the buffer, and read in the file contents:

>>> import os

>>> from ctypes import *

>>> buffLen = c_uint32()

>>> buffLen.value = os.path.getsize('tmp.txt')

>>> buff = (c_char * buffLen.value)()

>>> open('tmp.txt').readinto(buf)

15

>>> buff.value

'This is a test.'

Regarding your two other questions, I'd set up the function prototype like this:

lib = CDLL(path_to_dll)

isImageValid = lib.isImageValid

isImageValid.argtypes = c_char_p, POINTER(c_uint32), c_int, c_int, c_uint32

isImageValid.restype = c_bool

ctypes will automatically pass buffLen by reference given the above argtypes definition. You can also explicitly use byref(buffLen).

CDLL is for the cdecl (C declaration) calling convention, in which the caller cleans up the stack. This allows variadic functions such as printf. WinDLL is for the stdcall convention, in which the callee cleans up the stack. stdcall is mostly used by the 32-bit Win32 API, such as Kernel32 functions. See the Wikipedia article on x86 calling conventions.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值