假设我想从 Python 中调用一些 Rust 代码。假设我的
lib.rs
看起来像这样:
#[no_mangle]
pub extern fn add(left: i32, right: i32) -> i32 {
return left+right;
}
假设我使用
ctypes
从 Python 调用这段代码,如下所示:
import ctypes
def rust_add(left, right):
rust_lib = ctypes.CDLL("path/to/the/so/file")
return rust_lib.add(left, right)
那么以上安全吗?
即使是我——对 Rust 的掌握极其薄弱——也可以预见到一个问题是“整数溢出”。我想,如果 left
或
right
大于 2^32,就会导致不好的事情发生:Rust 要么会遇到运行时错误(最有可能),要么只会返回愚蠢的答案(最坏的情况下)。 Python 中的一些类型检查(也许使用 NumPy 的 uint32
)是否足以防止此问题?工作中的溢出
总结
c_int
类型,
其大小取决于平台。超过此大小的值将被截断。如果 c_int
碰巧不是 32 位,这将导致 Rust 意义上的未定义行为(您最终会使用不正确的调用约定来调用 rust 函数)。在这种情况下,这可能不是您想要的。
因此我推荐以下Python代码:
def rust_add(left, right):
rust_lib = ctypes.CDLL("path/to/the/so/file")
rust_add = rust_lib.add
rust_add.argtypes = [ctypes.c_int32, ctypes.c_int32]
rust_add.restype = ctypes.c_int32
return rust_add(left, right)
这样,无论平台如何,
ctypes
都会将参数和返回类型转换为正确的整数类型。
它仍然会截断较大的整数,并为其他 python 类型抛出异常。如果您想以不同的方式处理这些情况,您必须自己做。 有关
ctypes
如何处理类型转换的更多详细信息,我推荐他们出色的 文档
。