强制转换产生无效指针的函数引用?
Casting a function reference producing an invalid pointer?
我正在追踪第三方代码中的一个错误,并将其缩小到类似的范围内。
use libc::c_void;
pub unsafe fn foo() {}
fn main() {
let ptr = &foo as *const _ as *const c_void;
println!("{:x}", ptr as usize);
}
运行 在稳定版 1.38.0 上打印函数指针,但 beta (1.39.0-beta.6) 和 nightly return '1'。 (Playground)
_
被推断为什么以及为什么行为发生了变化?
我认为正确的转换方式应该是 foo as *const c_void
,但这不是我的代码。
What is the _
getting inferred to and why has the behaviour changed?
每次进行原始指针转换时,您只能更改一条信息(引用或原始指针;可变性;类型)。因此,如果您执行此转换:
let ptr = &foo as *const _
因为您已经从引用更改为原始指针,为 _
推断的类型必须 保持不变,因此是 [=14= 的类型], 这是函数 foo
.
的一些无法表达的类型
您可以直接转换为函数指针,而不是那样做,这在 Rust 语法中是可以表达的:
let ptr = foo as *const fn() as *const c_void;
至于为什么变了,就不好说了。这可能是夜间构建中的错误。值得 reporting it — 即使它不是错误,您也可能会从编译器团队那里得到关于实际发生的事情的很好解释!
此答案基于 the bug report motivated by this question.
上的回复
Rust 中的每个函数都有其单独的函数项类型,这与其他所有函数的函数项类型不同。出于这个原因,函数项类型的实例根本不需要存储任何信息——它指向的函数从它的类型中就很清楚了。所以
中的变量 x
let x = foo;
是一个大小为 0 的变量。
函数项类型在必要时隐式强制转换为函数指针类型。变量
let x: fn() = foo;
是指向任何函数的通用指针,签名为fn()
,因此需要存储指向它实际指向的函数的指针,因此[的大小=13=]是一个指针的大小。
如果您取一个函数的地址,&foo
,您实际上取的是一个零大小的临时值的地址。在 this commit to the rust
repo 之前,零大小的临时对象用于在堆栈上创建分配,而 &foo
返回该分配的地址。自此提交以来,零大小类型不再创建分配,而是使用魔术地址 1。这解释了不同版本的 Rust 之间的差异。
我正在追踪第三方代码中的一个错误,并将其缩小到类似的范围内。
use libc::c_void;
pub unsafe fn foo() {}
fn main() {
let ptr = &foo as *const _ as *const c_void;
println!("{:x}", ptr as usize);
}
运行 在稳定版 1.38.0 上打印函数指针,但 beta (1.39.0-beta.6) 和 nightly return '1'。 (Playground)
_
被推断为什么以及为什么行为发生了变化?
我认为正确的转换方式应该是 foo as *const c_void
,但这不是我的代码。
What is the
_
getting inferred to and why has the behaviour changed?
每次进行原始指针转换时,您只能更改一条信息(引用或原始指针;可变性;类型)。因此,如果您执行此转换:
let ptr = &foo as *const _
因为您已经从引用更改为原始指针,为 _
推断的类型必须 保持不变,因此是 [=14= 的类型], 这是函数 foo
.
您可以直接转换为函数指针,而不是那样做,这在 Rust 语法中是可以表达的:
let ptr = foo as *const fn() as *const c_void;
至于为什么变了,就不好说了。这可能是夜间构建中的错误。值得 reporting it — 即使它不是错误,您也可能会从编译器团队那里得到关于实际发生的事情的很好解释!
此答案基于 the bug report motivated by this question.
上的回复Rust 中的每个函数都有其单独的函数项类型,这与其他所有函数的函数项类型不同。出于这个原因,函数项类型的实例根本不需要存储任何信息——它指向的函数从它的类型中就很清楚了。所以
中的变量 xlet x = foo;
是一个大小为 0 的变量。
函数项类型在必要时隐式强制转换为函数指针类型。变量
let x: fn() = foo;
是指向任何函数的通用指针,签名为fn()
,因此需要存储指向它实际指向的函数的指针,因此[的大小=13=]是一个指针的大小。
如果您取一个函数的地址,&foo
,您实际上取的是一个零大小的临时值的地址。在 this commit to the rust
repo 之前,零大小的临时对象用于在堆栈上创建分配,而 &foo
返回该分配的地址。自此提交以来,零大小类型不再创建分配,而是使用魔术地址 1。这解释了不同版本的 Rust 之间的差异。