【问题标题】:Getting bit-pattern of bool in Swift在 Swift 中获取 bool 的位模式
【发布时间】:2015-03-14 20:31:07
【问题描述】:

在 ObjC 中,可以通过将 bool 的位模式转换为 UInt8 来检索它。

例如

  • 真 => 0x01
  • 假 => 0x00

然后可以在进一步的位操作操作中使用此位模式。


现在我想在 Swift 中做同样的事情。

到目前为止我的工作是

UInt8(UInt(boolValue))

但这看起来不是首选方法。

我还需要在 O(1) 中进行转换,而不需要依赖数据的分支。因此,不允许使用以下内容。

boolValue ? 1 : 0

另外,是否有一些关于 UInt8 和 UInt 初始化器实现方式的文档?例如如果要从 bool 转换的 UInt 初始化程序使用数据相关分支,我也不能使用它。

当然,后备始终是使用进一步的按位运算来完全避免布尔值(例如Check if a number is non zero using bitwise operators in C)。


  • Swift 是否提供了一种优雅的方式来访问 Bool 的位模式/将其转换为 UInt8,在 O(1) 中无需依赖数据的分支?

【问题讨论】:

    标签: swift int boolean type-conversion bit-manipulation


    【解决方案1】:

    如有疑问,请查看生成的汇编代码:)

    func foo(someBool : Bool) -> UInt8 {
        let x = UInt8(UInt(someBool))
        return x
    }
    

    用 ("-O" = "Compile with optimizations") 编译

    xcrun -sdk macosx swiftc -emit-assembly -O main.swift

    给予

    .globl __TF4main3fooFSbVSs5UInt8 .align 4, 0x90 __TF4main3fooFSbVSs5UInt8: .cfi_startproc pushq %rbp Ltmp2: .cfi_def_cfa_offset 16 Ltmp3: .cfi_offset %rbp, -16 movq %rsp, %rbp ltmp4: .cfi_def_cfa_register %rbp callq __TFE10FoundationSb19_bridgeToObjectiveCfSbFT_CSo8NSNumber movq %rax, %rdi callq __TFE10FoundationSuCfMSuFCSo8NSNumberSu movzbl %al, %ecx cmpq %rcx, %rax jne LBB0_2 流行音乐%rbp 回复

    函数名可以用

    $ xcrun -sdk macosx swift-demangle __TFE10FoundationSb19_bridgeToObjectiveCfSbFT_CSo8NSNumber __TFE10FoundationSuCfMSuFCSo8NSNumberSu _TFE10FoundationSb19_bridgeToObjectiveCfSbFT_CSo8NSNumber ---> ext.Foundation.Swift.Bool._bridgeToObjectiveC (Swift.Bool)() -> ObjectiveC.NSNumber _TFE10FoundationSuCfMSuFCSo8NSNumberSu ---> ext.Foundation.Swift.UInt.init (Swift.UInt.Type)(ObjectiveC.NSNumber) -> Swift.UInt

    没有采用Bool 参数的UInt 初始化程序。 所以智能编译器使用了 Swift 之间的自动转换 和 Foundation 类型并生成一些代码,例如

    let x = UInt8(NSNumber(bool: someBool).unsignedLongValue)
    

    两个函数调用可能效率不高。 (而且它没有 如果你只有import Swift,没有Foundation,则编译。)

    现在您假设数据相关分支的另一种方法:

    func bar(someBool : Bool) -> UInt8 {
        let x = UInt8(someBool ? 1 : 0)
        return x
    }
    

    汇编代码是

    .globl __TF4main3barFSbVSs5UInt8 .align 4, 0x90 __TF4main3barFSbVSs5UInt8: pushq %rbp movq %rsp, %rbp andb $1, %dil 移动 %dil, %al 流行音乐%rbp 回复

    没有分支,只是与0x01 的“AND”操作!

    因此,我认为没有理由不使用这种“直接”转换。 然后,您可以使用 Instruments 进行分析以检查它是否是瓶颈 你的应用程序。

    【讨论】:

      【解决方案2】:

      @martin-r 的回答更有趣:-),但这可以在操场上完成。

      // first check this is true or you’ll be sorry...
      sizeof(Bool) == sizeof(UInt8)
      
      let t = unsafeBitCast(true, UInt8.self)   // = 1
      let f = unsafeBitCast(false, UInt8.self)  // = 0
      

      【讨论】:

      • 我也检查过,生成的汇编代码与UInt8(someBool ? 1 : 0)完全相同。这就是为什么我限制回答“安全”方法:)
      • 有趣,我对我更喜欢哪种语法感到矛盾,因为位转换清楚地表明了代码的意图很容易阅读,但又是不安全的......
      • 确实很有趣。我敢打赌 unsafeBitCast 只是复制字节。但是对于 UInt8 有 5 个案例的枚举的 unsafeBitCast 实际上会与 0x07 进行 AND,因此编译器会使用真正使用哪些位的信息。
      • 有点喜欢这种语法,因为编译器可能会改变它处理第一个答案的方式。虽然不安全,但此解决方案更为明确。尽管如此,第一个答案还是提供了有关如何实际检查编译可能无法按假设工作的见解。会接受这个答案,因为 Airspeed 的声誉较低。
      猜你喜欢
      • 2014-10-24
      • 2014-11-07
      • 2021-03-03
      • 1970-01-01
      • 1970-01-01
      • 2016-03-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多