在Swift中获得bool的位模式

时间:2015-03-14 10:43:44

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

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

e.g。

  • true => 0×01
  • false => 0×00

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


现在我想在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)。


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

2 个答案:

答案 0 :(得分:4)

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

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

编译为(“ - O”=“编译优化”)

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

没有UInt初始值设定项采用Bool参数。 所以智能编译器已经使用了Swift之间的自动转换 和基础类型并生成一些代码,如

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

两个函数调用可能效率不高。 (而事实并非如此 如果你只有import Swift,没有基金会就编译。)

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

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

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

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

答案 1 :(得分: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