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

Roe*_*Roe 5 c python ctypes pointers

我正在尝试使用 cTypes 将字符串(作为指针)从 python 传递到 C 函数。

\n\n

c 函数需要获取指向字符串(字符数组)的指针,但我还没有成功地让它与多个字符一起工作,但我唯一的成功(有点成功,看看输出)是使用 1 个字符和希望得到一些帮助!

\n\n

我需要将字符串的指针发送到 char - (unsigned char * 输入)

\n\n

我的Python代码:

\n\n
def printmeP(CHAR):\n    print("In Print function")\n    print(CHAR)\n    c_sends = pointer(c_char_p(CHAR.encode(\'utf-8\')))\n    print("c_sends: ")\n    print(c_sends[0])\n    python_p_printme(c_sends)\n    print("DONE function - Python")\n    print(c_sends[0])\n    return\n\n\nfrom ctypes import c_double, c_int,c_char, c_wchar,c_char_p, c_wchar_p, pointer, POINTER,create_string_buffer,  byref, CDLL\nimport sys\n\nlib_path = \'/root/mbedtls/programs/test/mylib_linux.so\' .format(sys.platform)\n\n\nCHAR = "d"\n\ntry:\n    mylib_lib = CDLL(lib_path)\nexcept:\n     print(\'STARTING...\' )\npython_p_printme = mylib_lib.printme\npython_p_printme.restype = None\nprintmeP(CHAR)\n\n\n
Run Code Online (Sandbox Code Playgroud)\n\n

我的C代码:

\n\n
#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\nvoid printme(char * param) {\n    printf("\\nStart c Function!\\n");\n    printf("%s\\n Printing param\\n ", param);\n    char add = \'!\';\n    strncat(param, &add, 1);\n\n    printf("%s\\n Printing param\\n ", param);\n    printf("Function Done - c\\n");\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

我的输出:

\n\n
In Print function\nd <--- this is what i am sending\nc_sends: \nb\'d\' <--- this is after encoding\n\xef\xbf\xbd\xef\xbf\xbd[\xef\xbf\xbd <-------------=|\n Printing param       |\n \xef\xbf\xbd\xef\xbf\xbd[\xef\xbf\xbd               | This is the c code print\n Printing param        | **Question:** Why does it print \'\xef\xbf\xbd\' and no what\'s supposed to be printed\n Function Done - c <--=|\nDONE function - Python\nb\'d!\' <--------------------- this is the last print that prints after the change.\n\n
Run Code Online (Sandbox Code Playgroud)\n\n

希望获得一些帮助,感谢所有参与的人:)

\n\n

诚挚的,\n罗伊

\n

Mar*_*nen 7

存在很多问题:

  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")
Run Code Online (Sandbox Code Playgroud)
  1. 还有一个更微妙的问题。虽然程序此时可能看起来可以工作,但 Python 字符串是不可变的,因此如果调用的函数需要可变字符串,则必须使用create_unicode_buffer(for c_wchar_p) 或create_string_buffer(for c_char_p) 分配可变缓冲区;否则,strcatC 代码中的 将会损坏 Python 字符串。

这是一个完整的示例:

测试.cpp

def printmeP(CHAR):
    print("In Print function")
    print(CHAR)
    python_p_printme(CHAR.encode())
    print("DONE function - Python")
Run Code Online (Sandbox Code Playgroud)

测试.py

#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
Run Code Online (Sandbox Code Playgroud)

输出:

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)
Run Code Online (Sandbox Code Playgroud)

create_string_buffer请注意,如果 C 函数不更改缓冲区(例如 C 参数为 ),则不需要使用const char*。然后你就可以打电话了printme(b'test string')


Ste*_*cht 2

您可以使用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 必须是指定数组大小的整数,或者是用于初始化数组项的字节对象。

您可以将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"))
Run Code Online (Sandbox Code Playgroud)

它将输出:

Start c Function!
Hello World
...
print on python side: Hello World!
Run Code Online (Sandbox Code Playgroud)

在控制台上。