在 C++ 中,我在共享库中创建了一个 C 链接函数,如下所示:
#include <iostream>
extern "C" int myfunc()
{
std::cout << "Hello myfunc" << std::endl;
return 1;
}
注意该函数不需要任何参数,如果有人尝试使用参数调用它,我想生成一个错误。
我打算使用 ctypes 从 python 调用该函数,如下所示:
#!/usr/bin/python3
from ctypes import *
libmylib = cdll.LoadLibrary("./libmylib.so")
libmylib.myfunc.argtypes = []
return_code = libmylib.myfunc()
print(f"return_code={return_code:d}")
当我运行 python 脚本时,它会产生预期的输出:
Hello myfunc
return_code=1
为了测试它,我将函数的调用从 python 更改为另外传递一些参数,即我想要拒绝的行为。 例如:
return_code = libmylib.myfunc(123)
#or
return_code = libmylib.myfunc("123")
但是它仍然执行 myfunc 没有任何错误,并且似乎只是忽略了我“错误”提供了一些参数。
我尝试更改 argtypes 行,但似乎没有任何行为具有所需的行为:
libmylib.myfunc.argtypes = None
#or
libmylib.myfunc.argtypes = ()
ctypes 是否有可能检测并拒绝这些参数,或者我是否只需要接受 myfunc 可以使用额外的参数调用,而我应该忽略它们,而不是对此如此挑剔?
我可以在 python 中编写一个包装垫片函数,它可以检测额外的参数并在检测发生时生成错误,但实际上我希望避免这样做。
正如 EmilioSilva 在他的评论中提到的,这是设计使然。 引用自: https://docs.python.org/3/library/ctypes.html#ctypes._FuncPtr.argtypes
使用 C 调用约定的函数也接受其他未指定的参数
因此,为了获得所需的行为,我们需要一个垫片包装器。
在我们考虑函数没有参数的情况下,它是一个非常简单的垫片包装器:
def myfunc():
return libmylib.myfunc()
不带参数调用 myfunc 可按预期工作:
return_code = myfunc()
print(f"return_code={return_code:d}")
使用 args 调用 myfunc 也会根据需要失败:
# trigger an error when the caller tries to do this
return_code = myfunc(123)
这是错误...
Traceback (most recent call last):
File "testmyfunc.py", line 15, in <module>
return_code = myfunc(123)
TypeError: myfunc() takes 0 positional arguments but 1 was given