python: ctypes, read POINTER(c_char) in python

后端 未结 2 368
情书的邮戳
情书的邮戳 2021-01-23 19:13

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/

相关标签:
2条回答
  • 2021-01-23 19:56

    If you truly have a POINTER(c_char) type, it is subscriptable. In the future provide code that reproduces your issue:

    >>> p = cast(create_string_buffer(b'Hello, world!'),POINTER(c_char))
    >>> p
    <ctypes.LP_c_char object at 0x000001C2F6B58848>
    >>> p[0]
    b'H'
    >>> p[:14]
    b'Hello, world!\x00'
    >>> cast(p,c_char_p).value  # only if known to be nul-terminated
    b'Hello, world!'
    
    0 讨论(0)
  • 2021-01-23 20:12

    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.
    
    0 讨论(0)
提交回复
热议问题