cTypes -将字符串作为指针从python传递到c

c3frrgcw  于 2023-06-21  发布在  Python
关注(0)|答案(2)|浏览(166)

我尝试使用cTypes从python向C函数传递一个字符串(作为指针)。
c函数需要获取一个指向字符串(字符数组)的指针,但我还没有成功地让它与多个字符一起工作,但我唯一的成功(有点成功,看看输出)是1个字符,并希望得到一些帮助!
我需要发送一个字符串的指针到char -(unsigned char * input)

我的Python代码:

def printmeP(CHAR):
    print("In Print function")
    print(CHAR)
    c_sends = pointer(c_char_p(CHAR.encode('utf-8')))
    print("c_sends: ")
    print(c_sends[0])
    python_p_printme(c_sends)
    print("DONE function - Python")
    print(c_sends[0])
    return

from ctypes import c_double, c_int,c_char, c_wchar,c_char_p, c_wchar_p, pointer, POINTER,create_string_buffer,  byref, CDLL
import sys

lib_path = '/root/mbedtls/programs/test/mylib_linux.so' .format(sys.platform)

CHAR = "d"

try:
    mylib_lib = CDLL(lib_path)
except:
     print('STARTING...' )
python_p_printme = mylib_lib.printme
python_p_printme.restype = None
printmeP(CHAR)

我的C代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void printme(char * param) {
    printf("\nStart c Function!\n");
    printf("%s\n Printing param\n ", param);
    char add = '!';
    strncat(param, &add, 1);

    printf("%s\n Printing param\n ", param);
    printf("Function Done - c\n");
}

我的输出:

In Print function
d <--- this is what i am sending
c_sends: 
b'd' <--- this is after encoding
��[� <-------------=|
 Printing param       |
 ��[�               | This is the c code print
 Printing param        | **Question:** Why does it print '�' and no what's supposed to be printed
 Function Done - c <--=|
DONE function - Python
b'd!' <--------------------- this is the last print that prints after the change.

希望能得到一些帮助,感谢所有参与的人:)
真诚的,罗伊

a64a0gku

a64a0gku1#

存在若干问题:
1.为函数定义.argtypes。它将捕获传递不正确参数的错误。添加下面的行,并注意它是复数,是参数类型的元组。逗号构成一个1元组:
python_p_printme.argtypes = c_char_p,
1.一旦你做了这个修改,你会得到一个错误,因为这段代码:
c_sends = pointer(c_char_p(CHAR.encode('utf-8')
实际上是发送一个C char**(指向c_char_p的指针)。一旦你正确地设置了argtypes,你就可以用一个字节字符串调用这个函数,它就会工作。您的函数变为:

def printmeP(CHAR):
    print("In Print function")
    print(CHAR)
    python_p_printme(CHAR.encode())
    print("DONE function - Python")

1.还有一个更微妙的问题。虽然程序在这一点上看起来可以工作,但Python字符串是不可变的,因此如果调用的函数需要一个可变字符串,则必须使用create_unicode_buffer(对于c_wchar_p)或create_string_buffer(对于c_char_p)分配一个可变缓冲区;否则,C代码中的strcat将损坏Python字符串。
下面是一个完整的例子:
test.cpp

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// For Windows compatibility
#ifdef _WIN32
#   define API __declspec(dllexport)
#else
#   define API
#endif

// For C++ compiler compatibility
#ifdef __cplusplus
extern "C" {
#endif

API void alter_me(char* param, size_t length) {
    // truncates if additional info exceeds length
    strncat_s(param, length, " adding some info", length - 1);
}

#ifdef __cplusplus
}
#endif

test.py

from ctypes import *

lib = CDLL('./test')
alter_me = lib.alter_me
alter_me.argtypes = c_char_p,c_size_t
alter_me.restype = None

data = create_string_buffer(b'test',size=10)
alter_me(data,sizeof(data))
print(data.value)

data = create_string_buffer(b'test',size=50)
alter_me(data,sizeof(data))
print(data.value)

输出:

b'test addi'
b'test adding some info'

注意,如果C函数不改变缓冲区,例如C参数是const char*,则不需要使用create_string_buffer。然后你可以调用printme(b'test string')

snz8szmq

snz8szmq2#

你可以使用create_string_buffer。
文档可以在这里找到:https://docs.python.org/3/library/ctypes.html#ctypes.create_string_buffer
ctypes.create_string_buffer(init_or_size,size=None)
这个函数创建一个可变字符缓冲区。返回的对象是c_char的ctypes数组。
init_or_size必须是指定数组大小的整数,或者是用于初始化数组项的bytes对象。
使用buf.value.decode("utf-8")可以将缓冲区转换回UTF-8 python字符串。
你的C代码库的一个小例子可能看起来像这样:

from ctypes import *

mylib_lib = cdll.LoadLibrary("<your-lib>")
mylib_lib.printme.argtypes = c_char_p,

buf = create_string_buffer(128)
buf.value = b'Hello World'
mylib_lib.printme(buf)
print("print on python side:", buf.value.decode("utf-8"))

它将输出:

Start c Function!
Hello World
...
print on python side: Hello World!

在控制台上。

相关问题