Swift 是MemoryLayout<;T>;。大小/步幅/对齐编译时间?

Swift 是MemoryLayout<;T>;。大小/步幅/对齐编译时间?,swift,memory-layout,Swift,Memory Layout,作为参考,在C/C++中,等价的(sizeofoperator)是编译时,可以与模板编程(泛型)一起使用 我在Swift算法俱乐部寻找通用数据结构的实现,并偶然发现了他们对位集的实现: public struct BitSet { private(set) public var size: Int private let N = 64 public typealias Word = UInt64 fileprivate(set) public var words: [Word]

作为参考,在C/C++中,等价的(
sizeof
operator)是编译时,可以与模板编程(泛型)一起使用

我在Swift算法俱乐部寻找通用数据结构的实现,并偶然发现了他们对位集的实现:

public struct BitSet {
  private(set) public var size: Int

  private let N = 64
  public typealias Word = UInt64
  fileprivate(set) public var words: [Word]

  public init(size: Int) {
    precondition(size > 0)
    self.size = size

    // Round up the count to the next multiple of 64.
    let n = (size + (N-1)) / N
    words = [Word](repeating: 0, count: n)
  }

  <clipped>
编辑:从函数的通用/非通用版本添加一些反汇编

非通用swift:

func getSizeOfInt() -> Int {
  return MemoryLayout<UInt64>.size
}
func getSizeOfInt()->Int{
返回MemoryLayout.size
}
生成此反汇编:

(lldb) disassemble --frame
MemoryLayout`getSizeOfInt() -> Int:
    0x1000013c0 <+0>:  pushq  %rbp
    0x1000013c1 <+1>:  movq   %rsp, %rbp
    0x1000013c4 <+4>:  movl   $0x8, %eax
->  0x1000013c9 <+9>:  popq   %rbp
    0x1000013ca <+10>: retq   
(lldb) disassemble --frame
MemoryLayout`getSizeOf<A> (A) -> Int:
    0x100001390 <+0>:  pushq  %rbp
    0x100001391 <+1>:  movq   %rsp, %rbp
    0x100001394 <+4>:  subq   $0x20, %rsp
    0x100001398 <+8>:  movq   %rsi, -0x8(%rbp)
    0x10000139c <+12>: movq   %rdi, -0x10(%rbp)
->  0x1000013a0 <+16>: movq   -0x8(%rsi), %rax
    0x1000013a4 <+20>: movq   0x88(%rax), %rcx
    0x1000013ab <+27>: movq   %rcx, -0x18(%rbp)
    0x1000013af <+31>: callq  *0x20(%rax)
    0x1000013b2 <+34>: movq   -0x18(%rbp), %rax
    0x1000013b6 <+38>: addq   $0x20, %rsp
    0x1000013ba <+42>: popq   %rbp
    0x1000013bb <+43>: retq   
    0x1000013bc <+44>: nopl   (%rax)
MyApp`getSizeOfInt64():
    0x1000015a0 <+0>:  pushq  %rbp
    0x1000015a1 <+1>:  movq   %rsp, %rbp
    0x1000015a4 <+4>:  movl   $0x8, %eax
    0x1000015a9 <+9>:  popq   %rbp
    0x1000015aa <+10>: retq  
MyApp`getSizeOf<A>(_:):
    0x100001590 <+0>:  pushq  %rbp
    0x100001591 <+1>:  movq   %rsp, %rbp
    0x100001594 <+4>:  movq   %rsi, -0x8(%rbp)
    0x100001598 <+8>:  movq   %rdi, -0x10(%rbp)
->  0x10000159c <+12>: movq   -0x8(%rsi), %rsi
    0x1000015a0 <+16>: movq   0x88(%rsi), %rax
    0x1000015a7 <+23>: popq   %rbp
    0x1000015a8 <+24>: retq   
(lldb)反汇编--帧
MemoryLayout`getSizeOfInt()->Int:
0x100001C0:pushq%rbp
0x1000013c1:movq%rsp,%rbp
0x1000013c4:movl$0x8,%eax
->0x100001C9:popq%rbp
0x1000013ca:retq
基于0x8常量,这看起来像是基于@Charles Srstka答案的编译时常量

通用swift实现如何

func getSizeOf<T>(_ t:T) -> Int {
  return MemoryLayout<T>.size
}
func getSizeOf(\ut:t)->Int{
返回MemoryLayout.size
}
生成此分解:

(lldb) disassemble --frame
MemoryLayout`getSizeOfInt() -> Int:
    0x1000013c0 <+0>:  pushq  %rbp
    0x1000013c1 <+1>:  movq   %rsp, %rbp
    0x1000013c4 <+4>:  movl   $0x8, %eax
->  0x1000013c9 <+9>:  popq   %rbp
    0x1000013ca <+10>: retq   
(lldb) disassemble --frame
MemoryLayout`getSizeOf<A> (A) -> Int:
    0x100001390 <+0>:  pushq  %rbp
    0x100001391 <+1>:  movq   %rsp, %rbp
    0x100001394 <+4>:  subq   $0x20, %rsp
    0x100001398 <+8>:  movq   %rsi, -0x8(%rbp)
    0x10000139c <+12>: movq   %rdi, -0x10(%rbp)
->  0x1000013a0 <+16>: movq   -0x8(%rsi), %rax
    0x1000013a4 <+20>: movq   0x88(%rax), %rcx
    0x1000013ab <+27>: movq   %rcx, -0x18(%rbp)
    0x1000013af <+31>: callq  *0x20(%rax)
    0x1000013b2 <+34>: movq   -0x18(%rbp), %rax
    0x1000013b6 <+38>: addq   $0x20, %rsp
    0x1000013ba <+42>: popq   %rbp
    0x1000013bb <+43>: retq   
    0x1000013bc <+44>: nopl   (%rax)
MyApp`getSizeOfInt64():
    0x1000015a0 <+0>:  pushq  %rbp
    0x1000015a1 <+1>:  movq   %rsp, %rbp
    0x1000015a4 <+4>:  movl   $0x8, %eax
    0x1000015a9 <+9>:  popq   %rbp
    0x1000015aa <+10>: retq  
MyApp`getSizeOf<A>(_:):
    0x100001590 <+0>:  pushq  %rbp
    0x100001591 <+1>:  movq   %rsp, %rbp
    0x100001594 <+4>:  movq   %rsi, -0x8(%rbp)
    0x100001598 <+8>:  movq   %rdi, -0x10(%rbp)
->  0x10000159c <+12>: movq   -0x8(%rsi), %rsi
    0x1000015a0 <+16>: movq   0x88(%rsi), %rax
    0x1000015a7 <+23>: popq   %rbp
    0x1000015a8 <+24>: retq   
(lldb)反汇编--帧
MemoryLayout`getSizeOf(A)->Int:
0x10000390:pushq%rbp
0x10000391:movq%rsp,%rbp
0x10000394:subq$0x20,%rsp
0x10000398:movq%rsi,-0x8(%rbp)
0x1000039C:movq%rdi,-0x10(%rbp)
->0x100001A0:movq-0x8(%rsi),%rax
0x100001A4:movq 0x88(%rax),%rcx
0x1000013ab:movq%rcx,-0x18(%rbp)
0x100001AF:callq*0x20(%rax)
0x100003B2:movq-0x18(%rbp),%rax
0x100003B6:addq$0x20,%rsp
0x1000013ba:popq%rbp
0x1000013bb:retq
0x1000013bc:nopl(%rax)
上面的代码看起来不是编译时的?我还不熟悉mac/lldb上的汇编程序。

此代码:

func getSizeOfInt64() -> Int {
    return MemoryLayout<Int64>.size
}
调用方式如下:
getSizeOf(UInt64.self)

生成此程序集:

MyApp`getSizeOfInt64():
    0x1000015a0 <+0>:  pushq  %rbp
    0x1000015a1 <+1>:  movq   %rsp, %rbp
    0x1000015a4 <+4>:  movl   $0x8, %eax
    0x1000015a9 <+9>:  popq   %rbp
    0x1000015aa <+10>: retq  
MyApp`getSizeOf<A>(_:):
    0x100001590 <+0>:  pushq  %rbp
    0x100001591 <+1>:  movq   %rsp, %rbp
    0x100001594 <+4>:  movq   %rsi, -0x8(%rbp)
    0x100001598 <+8>:  movq   %rdi, -0x10(%rbp)
->  0x10000159c <+12>: movq   -0x8(%rsi), %rsi
    0x1000015a0 <+16>: movq   0x88(%rsi), %rax
    0x1000015a7 <+23>: popq   %rbp
    0x1000015a8 <+24>: retq   
MyApp`getSizeOf(:):
0x100001590:pushq%rbp
0x100001591:movq%rsp,%rbp
0x100001594:movq%rsi,-0x8(%rbp)
0x100001598:movq%rdi,-0x10(%rbp)
->0x10000159c:movq-0x8(%rsi),%rsi
0x1000015a0:movq 0x88(%rsi),%rax
0x1000015a7:popq%rbp
0x1000015a8:retq

嘿,谢谢。我的汇编程序一般都生锈了,我根本没有玩过lldb。然而,我注意到在我的答案中添加的这段代码的“通用”版本中还有很多工作要做。我看到了你的新加入——你说的很有道理,也很有趣。在C++中,即使在编译时,也会计算编译时的siZeof的模板化版本。这是C++中模板函数的要点,您专门研究类型T和保留类型安全性。我将进一步研究为什么在这种情况下使用这些寄存器,并将您的答案标记为正确。