【问题标题】:Swift: How to use sizeof?斯威夫特:如何使用 sizeof?
【发布时间】: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


    【解决方案1】:

    Swift 3 现在有 MemoryLayout.size(ofValue:) 可以动态查找大小。

    如果你使用一个又使用MemoryLayout<Type> 的泛型函​​数会产生意想不到的结果,例如将协议类型的引用传递给它。这是因为——据我所知——编译器拥有在编译时填充值所需的所有类型信息,这在查看函数调用时并不明显。然后您将获得协议的大小,而不是当前值。

    【讨论】:

      【解决方案2】:

      斯威夫特 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 背后的原因。

      【讨论】:

      • 这让事情变得更简单、更容易理解。感谢苹果! (讽刺).....
      • 你如何用 Float 做到这一点?
      • 您使用.bitWidth 和.byteWidth。你提到.byteWidth 是错误的吗?
      • @AlexZavatone 不,它在冒号后面写的扩展名内。
      【解决方案3】:

      为 Swift 3 更新

      注意MemoryLayout&lt;T&gt;.size 的含义与 C/Obj-C 中的 sizeof 不同。你可以阅读这个旧线程https://devforums.apple.com/message/1086617#1086617

      Swift 使用泛型类型来明确表示该数字在编译时是已知的。

      总而言之,MemoryLayout&lt;Type&gt;.size 是单个实例所需的空间,而MemoryLayout&lt;Type&gt;.stride 是连续数组中连续元素之间的距离。 Swift 中的 MemoryLayout&lt;Type&gt;.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
      

      【讨论】:

      • 哇,这与 sizeof 过去所做的相比是一个非常严重的变化。当我们的团队过渡到 Swift 3 时导致了一些错误。
      • 我在 swift 2.3 中找不到 MemoryLayout
      【解决方案4】:

      在带有 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 函数返回对象的大小,以字节为单位。正确的?那么,当我将以下字符串作为参数时,为什么它会返回“24”? “11111111111”
      • 这是因为方式,在 Swift Unicode 中动态地解码字符串
      • 虽然这适用于内置类型,但我认为 sizeof 数组方法的价值有限。请参阅上面的大小与步幅讨论。任意结构的数组通常具有特殊的对齐要求,这将使实际节省的连续字节数更多。
      • 我不推荐这个。它给调用者一种动态查找类型的错觉,而实际上是静态查找。如果您传入协议类型的引用,您将获得协议的大小,而不是当前值。
      【解决方案5】:

      使用 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)
      猜你喜欢
      • 2017-07-22
      • 2017-03-24
      • 1970-01-01
      • 1970-01-01
      • 2018-02-13
      • 2017-05-26
      • 2016-02-08
      • 2017-11-13
      • 2015-08-19
      相关资源
      最近更新 更多