在Rust调用C函数时,能否用Option/NonNull处理指针?
问题
我在Windows平台下调用一个接收结构体指针的C函数,该结构体定义如下:
typedef struct { uint32_t *field; } Foo; void bar(Foo *foo);
由于NonNull自Rust 1.29版本起具有repr(transparent)特性,我考虑采用如下Rust表示方式:
use std::ptr::NonNull; #[derive(Default)] #[repr(C)] struct Foo { field: Option<NonNull<u32>>, } extern "system" { fn bar(foo: Option<NonNull<u32>>); }
请问上述写法是否可行,还是必须使用*mut来定义指针?
回答
你的写法部分可行但存在关键错误,具体分析如下:
结构体
Foo的定义是可行且推荐的
因为NonNull<T>具有repr(transparent),内存布局和*mut T完全一致;而Rust会将Option<NonNull<T>>优化为与*mut T相同的内存大小(用空指针表示None,非空指针表示Some),和C中uint32_t*的布局完全匹配。这种写法既能保证C交互的内存兼容性,又能利用Rust类型系统避免空指针的不安全操作,比直接用*mut u32更安全。extern块中bar的函数签名完全错误
C函数bar接收的是Foo*类型参数,但你写的Rust签名将参数定义为Option<NonNull<u32>>,与C端类型完全不匹配。正确的签名应该是接收*mut Foo或者Option<NonNull<Foo>>:extern "system" { fn bar(foo: *mut Foo); // 也可以用Option<NonNull<Foo>>,同样能安全处理空指针场景 // fn bar(foo: Option<NonNull<Foo>>); }
总结:结构体字段用Option<NonNull<u32>>是可行的,但必须修正bar的函数签名,使其匹配C端的Foo*类型。
内容的提问来源于stack exchange,提问作者rodrigocfd
相关产品推荐
相关产品推荐

