python - python 中 c_char ctypes 的输入类型无效

标签 python c header ctypes

在我的 C 头文件中我有:

long TEST_API test( 
            _IN____ const char arg1,
            _INOUT_ char arg2[512]
    );

我在我的 python 代码中导入了 ctypes 并且我将“kcOpCode”和“szXMLAdditionalParameters”传递给 eftUtility 函数如下:

utilityXml_bytes = bytearray(b'<xml><test>20</test></xml>')
utilityXMLparams = (ctypes.c_byte*512)(*utilityXml_bytes)

def test():
    eftUtilityRes = lib.test("s", utilityXMLparams)
    if (eftUtilityRes == 10):
        "success"
    elif(eftUtilityRes == -10):
        "type 2 error"
    else:
        "type 3 error"

但我不断收到“arg1”的无效输入类型错误。我在这里做错了什么?可能是编码问题?我实际上是在将 s 传递给我的函数吗?

最佳答案

您的函数的签名是 (const char arg1 ... ) 因此您必须将 char 作为第一个参数传递,而不是字符。这意味着一个字节而不是单个 char 字符串。为了测试它,我写了我的库

foo.c

#include <stdio.h>
void foo(const char v)
{
    printf("Hello, I'm a shared library %c\n",v);
}

并编译它

gcc -c -Wall -Werror -fpic foo.c
gcc -shared -o libfoo.so foo.o

现在通过 python 控制台调用它:

我的 python 脚本是:

>>> from ctypes import *
>>> lib = cdll.LoadLibrary("./libfoo.so")
>>> a=lib.foo(ord("s"))
Hello, I'm a shared library s
>>> a=lib.foo("s")
Hello, I'm a shared library D
>>> a=lib.foo(b"s")
Hello, I'm a shared library D

很明显,你需要的是ord("s")


还有一件事:这只是一个猜测,但您读取的错误可能来自将不正确的字符作为第一个参数读取的库。


通过大量编辑,我们可以看到如果我们不通过使用 ctypes 调用 C 库函数来使用正确的转换,我们可以犯多少错误假设或愚蠢的错误。现在我上面写的只是了解问题出在哪里很有用,但应该在 Python 2 和 Python 3 中工作的实际生产代码应该声明正确的函数接口(interface)并使用 b"s" 作为参数:

>>> lib.foo.argtypes = (c_char,)
>>> lib.foo.restype = None
>>> lib.foo(b"s") 
Hello, I'm a shared library s 

仅作记录:

[编辑]

正如@eryksun 在评论中正确指出的那样,不使用正确的类型转换调用 C 函数是非常不安全的:这就像在 C 中不使用原型(prototype),一切都变成了 int。所以如果你不设置函数 argtype 最好使用像这样的显式转换:

>>> a=lib.foo(c_char(ord("s"))) #Work Just on Python 3
Hello, I'm a shared library s
>>> a=lib.foo(c_char("s")) # Just Python 2.7
Hello, I'm a shared library s
>>> a=lib.foo(c_char(b"s")) # Python 2 and 3
Hello, I'm a shared library s

[编辑]

根据您的评论:您还可以使用 105 或十六进制值 0x73ord("s") 进行硬编码

>>> a=lib.foo(105)
Hello, I'm a shared library s
>>> a=lib.foo(0x73)
Hello, I'm a shared library s

[编辑]

正如@Dunes 所指出的,有一种方法可以告诉 python 如何通过 lib.foo.argtypes = (c_char,) 隐式地进行转换。但是你如何通过 b"s" 或简单地 "s" 构建你的 char 并不重要(在 python 2.7 上)。

>>> lib.foo.argtypes = (c_char,)
>>> a=lib.foo(b"s") 
Hello, I'm a shared library s
>>> a=lib.foo("s")  #Python 2.7
Hello, I'm a shared library s

在 Python 3 中,如果指定 argtypes 是强制性的,则使用 b"s":

>>> lib.foo.argtypes = (c_char,)
>>> a=lib.foo(b"s") 
Hello, I'm a shared library s
>>> a=lib.foo("s")  #Python 3.4
ctypes.ArgumentError: argument 1: <class 'TypeError'>: wrong type

关于python - python 中 c_char ctypes 的输入类型无效,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28202676/

相关文章:

python - 01208在python中有特殊含义还是python2.6.2的bug?

python - 使用索引数组跨多个轴重新排序 numpy 数组的最快方法

python - 寻找有条件的顺序模式

c - 处理正则表达式中的元字符

c - 填写C语言程序

php - 用php输出mp3

python - 使用 python csv 阅读器忽略 "blank"(未填充)行

java - 谁能解释为什么 C 和 Java 的输出不同?

Java BMP 头文件

c++ - 通过头文件确定.lib/.dll