2017-09-04 11 views
3

참조를 위해 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> 

, 내가 가진 것 Nsizeof(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는 다음 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 getSizeOfInt() -> Int { 
    return MemoryLayout<UInt64>.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) 

시간을 컴파일 보이지 않는 ... :

func getSizeOf<T>(_ t:T) -> Int { 
    return MemoryLayout<T>.size 
} 

이 분해를 생산? 아직 mac/lldb에서 어셈블러에 익숙하지 않습니다.

답변

2

이 코드 : MemoryLayout<Int64>.size은 참으로 컴파일 시간을 것으로 보인다,이에서

MyApp`getSizeOfInt64(): 
    0x1000015a0 <+0>: pushq %rbp 
    0x1000015a1 <+1>: movq %rsp, %rbp 
    0x1000015a4 <+4>: movl $0x8, %eax 
    0x1000015a9 <+9>: popq %rbp 
    0x1000015aa <+10>: retq 

:

func getSizeOfInt64() -> Int { 
    return MemoryLayout<Int64>.size 
} 

이 어셈블리를 생성합니다.

stridealignment에 대한 조립품을 확인하는 것은 독자에게 맡겨져 있지만 비슷한 결과가 나타납니다 (Int64의 경우 실제로 동일 함).

편집 : 우리는 일반적인 기능에 대해 얘기하는 경우, 분명히 더 많은 작업을 수행해야합니다

함수는 컴파일 타임에 크기를 얻고있는 유형을 알고, 따라서 단지 수 없습니다 때문에 상수를 넣는다.당신이 당신의 함수를 정의한다면, 그것은 당신의 예보다 좀 덜 작업을 수행하는 유형 대신 형식의 인스턴스를 취할 :

func getSizeOf<T>(_: T.Type) -> Int { 
    return MemoryLayout<T>.size 
} 

라는 같은 : getSizeOf(UInt64.self)

이 어셈블리를 생성 :

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 
+0

안녕하세요. 내 어셈블러는 일반적으로 녹슬었고 나는 lldb를 전혀 사용하지 않았다. 그러나 나는이 코드의 "일반"버전에서 더 많은 작업을 수행하는 것으로 보았습니다.이 코드를 제 답변에 추가했습니다. – Josh

+0

Btw, 위의 일반적인 impl 디 어셈블리는 -O0과 -O3에서 동일합니다. 나는 당신의 새로운 추가를 본다 - 당신이 말하는 것이 의미 있고 흥미 롭다. C++에서 sizeof의 템플릿 화 된 버전조차도 컴파일 타임에 계산되므로 * 컴파일 타임에 계산되므로 * 계산됩니다. C++에서 템플리트 된 함수의 요점은 T 유형을 전문으로하고 유형 안전성을 유지한다는 것입니다. 나는 왜이 레지스터들이이 경우에 사용되는지에 대해 자세히 살펴보고 답을 정확하게 표시 할 것입니다. – Josh

+0

편집 한 질문에 대한 답변을 편집했습니다. –