【发布时间】:2014-08-31 00:30:14
【问题描述】:
为了在使用 Swift 时与 C API 集成,我需要使用 sizeof 函数。在 C 中,这很容易。在 Swift 中,我陷入了类型错误的迷宫。
我有这个代码:
var anInt: Int = 5
var anIntSize: Int = sizeof(anInt)
第二行有错误“'NSNumber' 不是 'T.Type' 的子类型”。为什么会这样,我该如何解决?
【问题讨论】:
标签: swift
为了在使用 Swift 时与 C API 集成,我需要使用 sizeof 函数。在 C 中,这很容易。在 Swift 中,我陷入了类型错误的迷宫。
我有这个代码:
var anInt: Int = 5
var anIntSize: Int = sizeof(anInt)
第二行有错误“'NSNumber' 不是 'T.Type' 的子类型”。为什么会这样,我该如何解决?
【问题讨论】:
标签: swift
Swift 3 现在有 MemoryLayout.size(ofValue:) 可以动态查找大小。
如果你使用一个又使用MemoryLayout<Type> 的泛型函数会产生意想不到的结果,例如将协议类型的引用传递给它。这是因为——据我所知——编译器拥有在编译时填充值所需的所有类型信息,这在查看函数调用时并不明显。然后您将获得协议的大小,而不是当前值。
【讨论】:
斯威夫特 4
从 Xcode 9 开始,现在有一个名为 .bitWidth 的属性,这提供了另一种为实例和整数类型编写 sizeof: 函数的方式:
func sizeof<T:FixedWidthInteger>(_ int:T) -> Int {
return int.bitWidth/UInt8.bitWidth
}
func sizeof<T:FixedWidthInteger>(_ intType:T.Type) -> Int {
return intType.bitWidth/UInt8.bitWidth
}
sizeof(UInt16.self) // 2
sizeof(20) // 8
但将sizeof: 替换为.byteWidth 会更有意义:
extension FixedWidthInteger {
var byteWidth:Int {
return self.bitWidth/UInt8.bitWidth
}
static var byteWidth:Int {
return Self.bitWidth/UInt8.bitWidth
}
}
1.byteWidth // 8
UInt32.byteWidth // 4
很容易看出为什么sizeof: 被认为是模棱两可的,但我不确定将它埋在 MemoryLayout 中是正确的做法。查看sizeof: 转换为MemoryLayout here 背后的原因。
【讨论】:
.bitWidth 和.byteWidth。你提到.byteWidth 是错误的吗?
为 Swift 3 更新
注意MemoryLayout<T>.size 的含义与 C/Obj-C 中的 sizeof 不同。你可以阅读这个旧线程https://devforums.apple.com/message/1086617#1086617
Swift 使用泛型类型来明确表示该数字在编译时是已知的。
总而言之,MemoryLayout<Type>.size 是单个实例所需的空间,而MemoryLayout<Type>.stride 是连续数组中连续元素之间的距离。 Swift 中的 MemoryLayout<Type>.stride 与 C/Obj-C 中的 sizeof(type) 相同。
举一个更具体的例子:
struct Foo {
let x: Int
let y: Bool
}
MemoryLayout<Int>.size // returns 8 on 64-bit
MemoryLayout<Bool>.size // returns 1
MemoryLayout<Foo>.size // returns 9
MemoryLayout<Foo>.stride // returns 16 because of alignment requirements
MemoryLayout<Foo>.alignment // returns 8, addresses must be multiples of 8
【讨论】:
在带有 Swift 3 beta 6 的 Xcode 8 中,没有函数 sizeof ()。但是,如果您愿意,您可以根据需要定义一个。这个新的 sizeof 函数可以按预期使用数组。旧的内置 sizeof 函数无法做到这一点。
let bb: UInt8 = 1
let dd: Double = 1.23456
func sizeof <T> (_ : T.Type) -> Int
{
return (MemoryLayout<T>.size)
}
func sizeof <T> (_ : T) -> Int
{
return (MemoryLayout<T>.size)
}
func sizeof <T> (_ value : [T]) -> Int
{
return (MemoryLayout<T>.size * value.count)
}
sizeof(UInt8.self) // 1
sizeof(Bool.self) // 1
sizeof(Double.self) // 8
sizeof(dd) // 8
sizeof(bb) // 1
var testArray: [Int32] = [1,2,3,4]
var arrayLength = sizeof(testArray) // 16
您需要 sizeof 函数的所有版本,以获取变量的大小以及数据类型和数组的正确大小。
如果你只定义第二个函数,那么 sizeof(UInt8.self) 和 sizeof(Bool.self) 将得到“8”。如果你只定义了前两个函数,那么 sizeof(testArray) 将得到 "8"。
【讨论】:
使用 sizeof 如下:
let size = sizeof(Int)
sizeof 使用类型作为参数。
如果您想要anInt 变量的大小,可以将dynamicType 字段传递给sizeof。
像这样:
var anInt: Int = 5
var anIntSize: Int = sizeof(anInt.dynamicType)
或者更简单(user102008指出):
var anInt: Int = 5
var anIntSize: Int = sizeofValue(anInt)
【讨论】:
let anIntSize = sizeofValue(anInt)