C/C++では、同等のもの(sizeof
オペレータ)がコンパイル時に使用され、テンプレートプログラミング(Generics)で使用できます。MemoryLayout <T> .size/stride/alignmentはコンパイル時間ですか?
私は、共通のデータ構造の実装のためにスウィフトのアルゴリズムクラブを通して見ていると、ビットセットのその実施に出くわした:はsizeofはコンパイル時定数演算子として存在している言語で
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>
、私が持っているでしょうN
をsizeof(Word) * 8
に設定するか、「magic number」64ではなくMemoryLayout<UInt64>.size * 8
に設定します。ここではそれほど魅力的ではありませんが、意味が分かりやすくするためのものです。
さらに、私は、同じ質問が適用される関数ファミリに気付いた(ref)。
static func size(ofValue value: T) -> Int
static func stride(ofValue value: T) -> Int
static func alignment(ofValue value: T) -> Int
編集:ジェネリック/汎用ではないバージョンの関数から逆アセンブリを追加します。
非ジェネリックSWIFT:
func getSizeOfInt() -> Int {
return MemoryLayout<UInt64>.size
}
この分解を生成:0x8の定数に基づいて
(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
、これは@Charles Srstkaの回答に基づいてコンパイル時定数のように見えます。
一般的な迅速な実装はどうですか?この分解プロデュース
func getSizeOf<T>(_ t:T) -> Int {
return MemoryLayout<T>.size
}
:
(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)
上記のコンパイル時間を見ていませんか...?私はまだmac/lldbのアセンブラには馴染みがない。
おかげで感謝します。私のアセンブラは一般的には錆びていて、私はlldbと全く遊んでいません。しかし、このコードの「汎用」バージョンでは、さらに多くの作業が減っていることに気付きました。これを私の答えに追加しました。 – Josh
Btwの場合、上記の一般的なimplの逆アセンブリは-O0と-O3で同じです。私はあなたの新しい追加を見ます - あなたが言うことは理にかなって面白いです。 C++では、sizeofのテンプレート化されたバージョンでさえ、コンパイル時に計算される*ため、コンパイル時に計算されます。それはC++のテンプレート関数のポイントなので、T型を専門とし、型の安全性を保持します。私はなぜこれらのレジスタがこの場合に使用されているかを詳しく見て、あなたの答えを正しいものにします。 – Josh
編集した質問に回答するための回答を編集しました。 –