python:ctypes,在python中读取POINTER(c_char) [英] python: ctypes, read POINTER(c_char) in python

查看:958
本文介绍了python:ctypes,在python中读取POINTER(c_char)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个ctypes字段,它是 POINTER(c_char)(根据文档,它必须对我的应用程序无效c_char_p: https://docs.python.org/3.7/library/ctypes.html#ctypes .c_char_p


对于也可能指向二进制数据的通用字符指针,必须使用POINTER(c_char)。


但是,ctypes本身推荐的用法似乎有缺点,它声称是指向单个字符的指针,但是,不是,它是指向字节数组的指针。



如何读取Python中ctypes功能(我知道 length )返回的数组?尝试像 foo [0:len] 那样建立索引,其中 foo POINTER(c_char ) TypeError爆炸:'c_char'对象不可下标



我可以使用 print(foo) print(foo [0])

我本以为 ctypes.cast 可能有用,但是我不知道该如何传递演员表的长度(就像将地址foo中的前N个字节解释为 bytes 对象一样)



编辑:一些代码。 / p>

所以我有一个结构:

  class foo(Structure): 
_fields_ = [( state,c_int),
( type,c_int),
( len,c_int),
( payload,POINTER( c_char))]#根据python字节以下未加密的字节数https://bytes.com/topic/python/answers/695078-ctypes-unsigned-char

我还有另一个functi在其上返回 POINTER(foo)

  lib3 = CDLL(。 ...所以)
f = lib3.f
f.restype = POINTER(foo)

我调用 f ,它返回 POINTER(foo)

  ptrf = f(....)

然后我尝试访问 ptrf.payload 。以下代码有效:

  def get_payload(ptr_to_foo):

val = cast(ptr_to_foo.contents .payload,c_char_p).value
return val [:ptr_to_foo.contents.len]

  ptrf = f(....)
get_payload(ptrf)

我想知道 get_payload 函数是否会更容易编写。

解决方案

[Python.Docs]:ctypes-用于Python的外部函数库状态,您必须 c_char_p 与二进制数据。
当然可以忽略,但是可能会出现意外(字符串被无声地截断)。


尽管可以在〜5 行中举例说明,粘贴整个内容:


dll.c

  #include< stdlib.h> 

#如果已定义(_WIN32)
#定义DLL_EXPORT __declspec(dllexport)
#else
#定义DLL_EXPORT
#endif

#define LEN 5


typedef struct CharPtrWrapperTag {
int len;
char *数据;
} CharPtrWrapper;


DLL_EXPORT CharPtrWrapper * get(){
CharPtrWrapper * ret = malloc(sizeof(CharPtrWrapper));
ret-> len = LEN;
ret-> data = malloc(LEN * sizeof(char));
ret-> data [0] =‘A’;
ret-> data [1] =‘B’;
ret-> data [2] = 0;
ret-> data [3] =‘C’;
ret-> data [4] =‘D’;
回程;
}


DLL_EXPORT void release(CharPtrWrapper * pWrap){
if(pWrap){
free(pWrap-> data);
pWrap-> data = NULL;
pWrap-> len = 0;
free(pWrap);
}
}

code.py

 #!/ usr / bin / env python3 

import sys
导入ctypes


DLL_NAME = ./dll.dll;
CharPtr = ctypes.POINTER(ctypes.c_char)

class CharPtrWrapper(ctypes.Structure):
_fields_ = [
( len,ctypes.c_int ),
(数据,CharPtr),
]


CharPtrWrapperPtr = ctypes.POINTER(CharPtrWrapper)


def main():
dll = ctypes.CDLL(DLL_NAME)
get = dll.get
get.restype = CharPtrWrapperPtr
版本= dll.release
release.argtypes = [CharPtrWrapperPtr]
wrap_ptr = get()
wrap = wrap_ptr.contents
print( {:} \n Len:{:d}。format( wrap,wrap.len))
用于范围内的idx(wrap.len):
print( {:d}:{:}。format(idx,wrap.data [idx] ))

s = ctypes.cast(wrap.data,ctypes.c_char_p).value [:wrap.len]
print( \nctypes.c_char_p cast:{:} ; .format(s))

CharArr = ctypes.c_char * wrap.len
char_arr = CharArr(* wrap.data [:wrap.len])
print(& CharArr:{:}。format(char_arr.raw))
发行(wrap_ptr)
print( \nDone。)


if __name__ == __main__:
print( Python {:s} on {:s} \n .format(sys.version,sys.platform))
main ()

输出


  [cfati @ CFATI-5510-0:e:\Work\Dev\StackOverflow\q055103298]> sopr.bat 
***在粘贴到StackOverflow(或其他)页面时,设置更短的提示以更好地适应***

[提示]> c:\安装\x86\Microsoft\Visual Studio社区\2015\vc\vcvarsall.bat x64

[提示]> dir / b
code.py
dll.c

[提示]> cl / nologo / DDLL / MD dll.c / link / NOLOGO / DLL /OUT:dll.dll
dll.c
创建库dll.lib和对象dll.exp

[提示]> dir / b
code.py
dll.c
dll.dll
dll.exp
dll.lib
dll.obj

[提示]> e:\Work\Dev\VEnvs\py_064_03.06.08_test0\Scripts\python.exe code.py
Python 3.6.8(tags / v3.6.8:3c6b436a57,2018年12月24日,00:16:47)[win32
$ b $上的[MSC v.1916 64位(AMD64)] b< __ main __。CharPtrWrapper对象位于0x000001279250D248>
Len:5
0:b'A'
1:b'B'
2:b'\x00'
3:b'C'
4:b'D'

ctypes.c_char_p演员:b'AB'
CharArr:b'AB\x00CD'

完成。



I have a ctypes field that is a POINTER(c_char) (it had to be, per the documentation, c_char_p didn't work for my application: https://docs.python.org/3.7/library/ctypes.html#ctypes.c_char_p)

For a general character pointer that may also point to binary data, POINTER(c_char) must be used.

However, this usage recommended by ctypes itself seems to have the downside that, it claims to be a pointer to a single character, however, it isn't, it's a pointer to an array of bytes.

How can I read the array returned by the ctypes fucntion (I know the length) in Python? Trying to index it like foo[0:len] where foo is a POINTER(c_char) blows up with TypeError: 'c_char' object is not subscriptable

I can print the first character of the bytestring using either print(foo) or print(foo[0])

I was thinking that ctypes.cast might work, however I don't know how to pass it the length of the cast (as in interpret the first N bytes from address foo as a bytes object)

EDIT: some code.

So I have a structure:

class foo(Structure):
_fields_ = [("state", c_int),
            ("type", c_int),
            ("len", c_int),
            ("payload", POINTER(c_char))]  # according to th following the python bytes are already unsinged https://bytes.com/topic/python/answers/695078-ctypes-unsigned-char

And I have another function that returns a POINTER(foo)

lib3 = CDLL(....so)
f = lib3.f
f.restype = POINTER(foo)

I call f, which returns a POINTER(foo):

ptrf = f(....)

And then I was trying to access ptrf.payload. The following code works:

def get_payload(ptr_to_foo):

    val = cast(ptr_to_foo.contents.payload, c_char_p).value
    return val[:ptr_to_foo.contents.len]

So I do

 ptrf = f(....)
 get_payload(ptrf)

I was wondering whether the get_payload function would be written more easily.

解决方案

As [Python.Docs]: ctypes - A foreign function library for Python states, you must not use c_char_p with binary data.
Of course that can be ignored, but then surprises (string silently truncated) may occur.

Although it could be exemplified in ~5 lines of code, pasting the whole thing:

dll.c:

#include <stdlib.h>

#if defined(_WIN32)
#  define DLL_EXPORT __declspec(dllexport)
#else
#  define DLL_EXPORT
#endif

#define LEN 5


typedef struct CharPtrWrapperTag {
    int len;
    char *data;
} CharPtrWrapper;


DLL_EXPORT CharPtrWrapper *get() {
    CharPtrWrapper *ret = malloc(sizeof(CharPtrWrapper));
    ret->len = LEN;
    ret->data = malloc(LEN * sizeof(char));
    ret->data[0] = 'A';
    ret->data[1] = 'B';
    ret->data[2] = 0;
    ret->data[3] = 'C';
    ret->data[4] = 'D';
    return ret;
}


DLL_EXPORT void release(CharPtrWrapper *pWrap) {
    if (pWrap) {
        free(pWrap->data);
        pWrap->data = NULL;
        pWrap->len = 0;
        free(pWrap);
    }
}

code.py:

#!/usr/bin/env python3

import sys
import ctypes


DLL_NAME = "./dll.dll"
CharPtr = ctypes.POINTER(ctypes.c_char)

class CharPtrWrapper(ctypes.Structure):
    _fields_ = [
        ("len", ctypes.c_int),
        ("data", CharPtr),
    ]


CharPtrWrapperPtr = ctypes.POINTER(CharPtrWrapper)


def main():
    dll = ctypes.CDLL(DLL_NAME)
    get = dll.get
    get.restype = CharPtrWrapperPtr
    release = dll.release
    release.argtypes = [CharPtrWrapperPtr]
    wrap_ptr = get()
    wrap = wrap_ptr.contents
    print("{:}\n    Len: {:d}".format(wrap, wrap.len))
    for idx in range(wrap.len):
        print("        {:d}: {:}".format(idx, wrap.data[idx]))

    s = ctypes.cast(wrap.data, ctypes.c_char_p).value[:wrap.len]
    print("\nctypes.c_char_p cast: {:}".format(s))

    CharArr = ctypes.c_char * wrap.len
    char_arr = CharArr(*wrap.data[:wrap.len])
    print("CharArr: {:}".format(char_arr.raw))
    release(wrap_ptr)
    print("\nDone.")


if __name__ == "__main__":
    print("Python {:s} on {:s}\n".format(sys.version, sys.platform))
    main()

Output:

[cfati@CFATI-5510-0:e:\Work\Dev\StackOverflow\q055103298]> sopr.bat
*** Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ***

[prompt]> "c:\Install\x86\Microsoft\Visual Studio Community\2015\vc\vcvarsall.bat" x64

[prompt]> dir /b
code.py
dll.c

[prompt]> cl /nologo /DDLL /MD dll.c  /link /NOLOGO /DLL /OUT:dll.dll
dll.c
   Creating library dll.lib and object dll.exp

[prompt]> dir /b
code.py
dll.c
dll.dll
dll.exp
dll.lib
dll.obj

[prompt]> "e:\Work\Dev\VEnvs\py_064_03.06.08_test0\Scripts\python.exe" code.py
Python 3.6.8 (tags/v3.6.8:3c6b436a57, Dec 24 2018, 00:16:47) [MSC v.1916 64 bit (AMD64)] on win32

<__main__.CharPtrWrapper object at 0x000001279250D248>
    Len: 5
        0: b'A'
        1: b'B'
        2: b'\x00'
        3: b'C'
        4: b'D'

ctypes.c_char_p cast: b'AB'
CharArr: b'AB\x00CD'

Done.

这篇关于python:ctypes,在python中读取POINTER(c_char)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆