
在Python中使用ctypes调用C函数时,若传入普通Unicode字符串(如"Test")给声明为c_char_p的参数,会因类型不匹配抛出ArgumentError;正确做法是显式传递字节串(如b'Test')或改用c_wchar_p配合Unicode字符串。
在python中使用ctypes调用c函数时,若传入普通unicode字符串(如"test")给声明为`c_char_p`的参数,会因类型不匹配抛出`argumenterror`;正确做法是显式传递字节串(如`b'test'`)或改用`c_wchar_p`配合unicode字符串。
该错误的根本原因在于:ctypes.c_char_p 对应 C 中的 char *,它期望接收一个字节序列(bytes),而非 Python 3 默认的 Unicode 字符串(str)。当您直接写 init_hello("Test") 时,传入的是 str 类型,ctypes 无法自动将其转换为 C 兼容的 char*,因此触发 TypeError: wrong type。
✅ 正确解决方案
方案一:使用字节串(推荐,跨平台、轻量)
将字符串显式编码为 bytes,并以 b'' 前缀书写:
import ctypes
lib = ctypes.cdll.LoadLibrary('./test.so')
hello = lib.hello
hello.argtypes = [ctypes.c_char_p]
hello.restype = None # 显式声明返回类型更安全(原C函数无返回值)
hello(b"Test") # ✅ 正确:传入 bytes 对象⚠️ 注意:
b"Test"是bytes类型,等价于"Test".encode('ascii')。若字符串含非ASCII字符(如"你好"),需确保编码一致,例如:hello("你好".encode('utf-8')) # ✅ 显式 UTF-8 编码
方案二:使用宽字符(适合 Unicode 密集场景)
修改 C 函数签名,使用 wchar_t*,并在 Python 中对应使用 c_wchar_p:
立即学习“Python免费学习笔记(深入)”;
C 端(shared.c):
#include <stdio.h>
#include <wchar.h>
void hello(wchar_t *name) {
wprintf(L"Hello, %ls\n", name); // 注意 L"..." 和 %ls
}编译(需链接 wchar 支持):
gcc -shared -fPIC shared.c -o test.so
Python 端:
import ctypes
lib = ctypes.cdll.LoadLibrary('./test.so')
hello = lib.hello
hello.argtypes = [ctypes.c_wchar_p] # ✅ 匹配 wchar_t*
hello.restype = None
hello("Test") # ✅ 直接传 str(自动转 wchar_t*)
hello("你好") # ✅ 原生支持 Unicode❌ 常见误区澄清
-
create_string_buffer("Test".encode())创建的是可变缓冲区,适用于需要 C 函数写入数据的场景(如输出参数),本例中仅需只读传参,无需额外封装。 -
loader.c中的hello(char *name);调用语法错误(不应带类型声明),且main()中hello(char *name)是非法 C 表达式——该文件实际未被使用,可忽略。 -
restype = c_bool与 C 函数void hello(...)不匹配,应设为None或ctypes.c_void_p。
总结
| 场景 | C 类型 | Python 类型 | 示例 |
|---|---|---|---|
| ASCII / UTF-8 字符串(通用) | char * |
bytes |
b"Hello" 或 "Hello".encode('utf-8')
|
| Unicode 字符串(需 C 端支持宽字符) | wchar_t * |
str |
"你好"(自动转换) |
牢记:ctypes 不做隐式字符串编码转换。明确数据类型边界,是避免 ArgumentError 的关键。


















