【问题标题】:Transmuting `bool` to `u8`将 `bool` 转换为 `u8`
【发布时间】:2016-04-28 20:07:22
【问题描述】:

以下代码在 amd64 上与 Rust 1.8 一起正常工作。

use std::mem;

fn main() {
    let f: u8 = unsafe { mem::transmute(false) };
    let t: u8 = unsafe { mem::transmute(true) };
    assert_eq!(0, f);
    assert_eq!(1, t);
}

我的问题是,我可以假设这将始终有效吗?我试图找到关于bool表示的参考,但我只找到了thisthis,但我认为这并不权威。

【问题讨论】:

  • 你为什么要这样做? (插入夸张的喘息。)
  • 为bool创建一个紧凑的选项类型,类似于github.com/llogiq/optional。可选的 crate 使用枚举,但不允许返回对内部值的引用。
  • 看不到与 let f: u8 = if boolValue { 1u8 } else { 0u8 } 之类的功能有任何区别(不确定确切的 rust 语法)。但是没有 transmute 的版本可以在不依赖任何编译器行为的情况下工作。
  • 我需要转换来达到我在另一条评论中描述的目的。

标签: rust


【解决方案1】:

布尔表示似乎非常严格。它表示为 1 和 0,但我想提醒您,如果出于某种疯狂的原因,如果您盲目地假设 true == <some u8 that isn't what Rust really uses>,这会发生一些奇怪的行为。这与您的问题相反,但我认为这很重要:

fn main() {
    use std::mem;

    let b: bool = unsafe {mem::transmute(4 as u8)};

    println!("{} {} {}", b, b == true, b == false);

    if b {
        println!("evaluates true");
    }

    if !b {
        println!("evaluates false");
    }

    let x: u8 = unsafe{mem::transmute(b)};

    println!("{}", x);

    let x = b as u8;

    println!("{}", x);
}

这会在我测试过的 Playground 上的几乎每个配置上产生不同的输出。在同一程序中经常出现明显的矛盾:

调试/稳定:

true true true
evaluates false
0
0

这意味着它打印为 true,将 true 与 true 和 false 进行比较,但在分支中评估为 false。并变回 0。

发布/稳定:

true false true
evaluates true
4
4

如果您使用 C 风格的 bool,这可能是您“期望的”,并且具有正确的转换行为。 (编辑:实际上,不,它不是。它打印错误!它将相反的结果与它的评估方式进行比较)。

调试/测试版:

true true true
evaluates false
4
4

与 Debug/Stable 相同,但可以正确转换回来(我认为这可能是已修复的错误)。

发布/测试版:

与发布/稳定版相同

调试/每晚:

与调试/测试版相同

发布/每晚:

与其他人的发布相同。

奖金

如果您将println!("{} {} {}", b, b == true, b == false); 更改为println!("{} {}", b, b == true);,您将获得不同的打印行为。

例如,在 Debug/Stable 上:

true false
evaluates false
0
0

此外,从1 as u8 转换在所有配置上都可以正常工作,因此这不仅仅是transmute 的问题。


这个故事的寓意是,虽然这不太可能改变,但如果发生这种情况,你可能会手上拿着一只地狱犬(或者你在 u8 上犯了一个错误,然后将它变回或用不安全的指针)。在大多数情况下,我可能会坚持使用完美工作且安全的my_bool as u8,尽管我知道您的用例可能会禁止这样做。

【讨论】:

  • 感谢您的回答。正如你所难过的,这与我的问题相反。无论如何,这是一个有趣的答案。
【解决方案2】:

2021 年更新The Rust reference 现在将 bool 的内存表示定义为等于 0 或 1 的 1 字节值:

布尔类型的对象的大小和对齐方式各为 1。值 false 具有位模式 0x00,值 true 具有位模式 0x01。具有布尔类型的对象具有任何其他位模式是未定义的行为。

【讨论】:

  • > 最后,这本书并不规范。它可能包含特定于 rustc 本身的细节,不应被视为 Rust 语言的规范。特别是github.com/rust-lang/reference/pull/940,是由合作者而非语言核心团队撰写的,因此我不会将其用作参考。
  • @Stargateur Rust 没有规范规范。如果参考书的这一页不打算定义 bool 的内存表示,我认为我们应该提交一个文档错误,因为这一页非常权威地陈述了一个表示。
  • @Stargateur 另外,根据该拉取请求,bool 的允许值已经在 src/behavior-considered-undefined.md... 中指定(参见 Files Changed 选项卡中的第一个文件)
【解决方案3】:

从来没有采用任何定义bool 表示的RFC。也就是说,作为一个实际问题,它不太可能改变。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2015-09-26
  • 2021-07-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多