简体   繁体   English

指针参数传入 python ctypes

[英]Pointer argument passing in python ctypes

I have the following c function.我有以下 c function。

/* returns (uint8_t *)outbuf */
uint8_t *func(uint8_t *inbuf, uint32_t inbuf_len, uint32_t *outbuf_len);

This function returns outbuf , the output length is unknown before calling the function so the function receives a pointer to the length as an argument outbuf_len , also the caller is responsible to free() outbuf . This function returns outbuf , the output length is unknown before calling the function so the function receives a pointer to the length as an argument outbuf_len , also the caller is responsible to free() outbuf .

I want to get the result of this function from python, so I started writing the following code:我想从 python 中得到这个 function 的结果,所以我开始编写以下代码:

import ctypes as ct

libb = ct.cdll.LoadLibrary('./a.so')
libb.func.restype = ct.c_char_p

inbuf = bytearray(inbuf_len)
inbuf = python_data
arr = ct.c_ubyte * inbuf_len

outbuf_len = ct.c_uint #there is no ct.c_uint_p...

outbuf = libb.func(arr.from_buffer_copy(inbuf), inbuf_len, outbuf_len)

print hexlify(outbuf) #prints only the first 4 bytes of outbuf

The problems i have is:我遇到的问题是:

  1. I didn't find pointer to uint in ctypes types, so how can I pass the outbuf_len pointer to the c function?我没有在ctypes类型中找到指向 uint 的指针,那么如何将outbuf_len指针传递给 c function?
  2. when printing the outbuf , only the first 4 bytes that are pointed by the pointer are printed.打印outbuf时,仅打印指针指向的前 4 个字节。
  3. How to free() the outbuf buffer from python?如何从 python 中释放() outbuf缓冲区?

I have the source of the c function so it is possible to change how arguments are passed the the c function. I have the source of the c function so it is possible to change how arguments are passed the the c function.

Thanks.谢谢。

If you'll be passing Python byte strings as the input buffer, here's a way to do it.如果您将传递 Python 字节字符串作为输入缓冲区,这是一种方法。 I made a minimal example of the C call:我做了一个 C 调用的最小示例:

test.c测试.c

#include <stdint.h>
#include <stdlib.h>

#define API __declspec(dllexport)

// double every character in the input buffer as an example
API uint8_t *func(uint8_t *inbuf, uint32_t inbuf_len, uint32_t *outbuf_len) {
    *outbuf_len = inbuf_len * 2;
    uint8_t* outbuf = malloc(*outbuf_len);
    for(uint32_t i = 0; i < inbuf_len; ++i) {
        outbuf[i*2] = inbuf[i];
        outbuf[i*2+1] = inbuf[i];
    }
    return outbuf;
}

API void freebuf(uint8_t* buf) {
    free(buf);
}

test.py测试.py

import ctypes as ct

dll = ct.CDLL('./test')

# c_char_p accepts Python byte strings and is compatible with C uint8_t*
# but don't use it for the output buffer because ctypes converts the pointer
# back to a Python byte string and you would lose access to the pointer for
# later freeing it.  Use POINTER(ct.c_char) to get the actual pointer back.
dll.func.argtypes = ct.c_char_p, ct.c_uint32, ct.POINTER(ct.c_uint32)
dll.func.restype = ct.POINTER(ct.c_char)
dll.freebuf.argtypes = ct.POINTER(ct.c_char),
dll.freebuf.restype = None

def func(inbuf):
    outlen = ct.c_uint32()  # create storage for the output length and pass by reference
    outbuf = dll.func(inbuf, len(inbuf), ct.byref(outlen))
    # Slicing the returned POINTER(c_char) returns a Python byte string.
    # If you used POINTER(c_uint8) for the return value instead,
    # you'd get a list of integer byte values.
    data = outbuf[:outlen.value]
    # Can free the pointer now if you want, or return it for freeing later
    dll.freebuf(outbuf)
    return data

print(func(b'ABC'))

Output: Output:

b'AABBCC'

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM