在 Swift 中获取 bool 的位模式

Getting bit-pattern of bool in Swift

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

例如

此位模式随后可用于进一步的位操作。


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

到目前为止我得到的工作是

UInt8(UInt(boolValue))

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

我还需要 O(1) 的转换,而不需要依赖于数据的分支。所以,像下面这样的东西是不允许的。

boolValue ? 1 : 0

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

当然,回退总是使用进一步的按位运算来完全避免 bool 值(例如 Check if a number is non zero using bitwise operators in C)。


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

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
    popq    %rbp
    retq

函数名可以用

分解
$ 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之间的自动转换 和基础类型并生成了一些代码,如

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    , %dil
    movb    %dil, %al
    popq    %rbp
    retq

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

因此我没有理由不使用此 "straight-forward" 转换。 然后您可以使用 Instruments 进行分析以检查它是否是 你的应用程序。

@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