是的,你应该这样做,因为它起作用的原因是 ctypes 的猜测。将int test_i(int i) 替换为int test_i(char i),你会得到堆栈损坏——因为Python 端给函数4 或8 个字节,而C 端只读取1 个字节。根据平台的不同,这可能会在一段时间内被忽视,或者逐渐耗尽你的堆栈,或者立即崩溃,或者什么都不会发生——无论如何,这种代码风格有异味。
ctypes 进行基本的类型转换,但在很多情况下它不会有帮助,因为 Python 类型系统比 C 的简单得多。例如,Python 端无法确定您传递的是 1 字节、2 字节、4 字节还是 8 字节整数,因为 Python 整数没有大小。 Python 只有双精度浮点数,而 C 端也有单精度和半精度,并且可能还具有特定于平台的精度。字符串和字节仅在 Python 端正确分离,而在 C 端使用 Unicode 通常是一团糟。目前尚不清楚您是想使用wchar_t[] 还是char[],您想如何终止您的字符串,您是否需要它,以及您想如何解决Python 字符串不变性。如果没有正确的argtypes,您将无法轻松传递结构和数组。
另外,别忘了注明restype:
libc.test_f.restype = c_int
默认情况下ctypes 假定所有函数都返回int,无论它适用于您的平台。根据调用约定,可能会使用 CPU 寄存器来返回结果——在这种情况下,您不会受到伤害,因为寄存器是否被读取都没有区别。在其他情况下,结果是通过堆栈传递的,而你搞砸了,因为没有消耗足够的堆栈(以及过度消耗)会导致堆栈损坏,函数的RET 将弹出错误的地址并在最好的情况下向 SIGSEGV 打招呼。在最坏的情况下,黑客会使用您的应用程序进行欺骗。
一般来说,argtypes 和 restype 是你的朋友,因为它们可以保护你的代码不会以不可预知的方式分崩离析,而且它们之所以需要,是因为 C 和 Python 中的一切都大相径庭。如果不是这样,没有人会因为 Zen 和电池而简单地强迫你使用这些。