在 Swift 中获取 bool 的位模式
Getting bit-pattern of bool in Swift
在 ObjC 中,可以通过将 bool 的位模式转换为 UInt8 来检索它。
例如
- 真 => 0x01
- 假 => 0x00
此位模式随后可用于进一步的位操作。
现在我想在 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) 中没有数据相关的分支?
如有疑问,请查看生成的汇编代码:)
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
在 ObjC 中,可以通过将 bool 的位模式转换为 UInt8 来检索它。
例如
- 真 => 0x01
- 假 => 0x00
此位模式随后可用于进一步的位操作。
现在我想在 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) 中没有数据相关的分支?
如有疑问,请查看生成的汇编代码:)
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