How can I use ctypes to pass a byteArray into a C function that takes a char* as its argument?

孤街浪徒 提交于 2019-12-23 22:33:20

问题


I have created a function in C which takes an int size and a char *buffer as arguments. I would like to use ctypes to call this function from python and pass in a python byteArray. I know that first you must compile the C file into a shared library (.so file) and use ctypes to call that function. Here's the code I have so far.

encrypt.c:

#include <stdio.h>
void encrypt(int size, unsigned char *buffer);
void decrypt(int size, unsigned char *buffer);

void encrypt(int size, unsigned char *buffer){
    for(int i=0; i<size; i++){
        unsigned char c = buffer[i];
        printf("%c",c);
    }
}
void decrypt(int size, unsigned char *buffer){
    for(int i=0; i<size; i++){
        unsigned char c = buffer[i];
        printf("%c",c);
    }
}

And here's the python file:

import ctypes

encryptPy = ctypes.CDLL('/home/aradhak/Documents/libencrypt.so')
hello = "hello"
byteHello = bytearray(hello)
encryptPy.encrypt(5,byteHello)
encryptPy.decrypt(5,byteHello)

Basically I want to call the C method from python, pass through a python byte array, and have it iterate through the array and print each element


回答1:


Mark's answer is quite helpful in that it passes a character array to C, which is what the OP really wanted, but in case there's folks finding their way here who really want to pass a byte-array, an approach seems to be to build a ctypes.c_char backed by the memory of your byte-array, and pass that.

note my example here disregards the argument declaration recommend by Mark, which indeed seems like a good idea.

import ctypes

# libFoo.c:
# (don't forget to use extern "C" if this is a .cpp file)
#
# void foo(unsigned char* buf, size_t bufSize) {
#   for (size_t n = 0; n < bufSize; ++n) {
#     buf[n] = n;
#   }
# }

fooLib = ctypes.cdll.LoadLibrary('./lib/libFoo.dylib')

ba = bytearray(10)

char_array = ctypes.c_char * len(ba)

fooLib.foo(char_array.from_buffer(ba), len(ba))

for b in ba:
  print b

# 0
# 1
# 2
# 3
# 4
# 5
# 6
# 7
# 8
# 9



回答2:


The minimum you need (Python 2) is:

hello = "hello"
encryptPy.encrypt(5,hello)
encryptPy.decrypt(5,hello)

But it is good to declare the argument types and return values as well. Full program:

#!python2
import ctypes

encryptPy = ctypes.CDLL('/home/aradhak/Documents/libencrypt.so')

encryptPy.encrypt.argtypes = (ctypes.c_int,ctypes.c_char_p)
encryptPy.encrypt.restype = None
encryptPy.decrypt.argtypes = (ctypes.c_int,ctypes.c_char_p)
encryptPy.decrypt.restype = None

hello = "hello"
encryptPy.encrypt(len(hello),hello)
encryptPy.decrypt(len(hello),hello)

Note that when passing a python byte string, consider the buffer immutable. In this case you only are reading the buffer, but if you need to allow the C function to mutate the string use:

hello = ctypes.create_string_buffer(5,'hello')

This works as well, but will be length 6. A terminating null will be included.

hello = ctypes.create_string_buffer('hello')


来源:https://stackoverflow.com/questions/37422662/how-can-i-use-ctypes-to-pass-a-bytearray-into-a-c-function-that-takes-a-char-as

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!