Wireframe

Raw 포인터 사용에 대해

https://developer.apple.com/documentation/swift/unsaferawpointer

UnsafeRawPointer 타입은 자동 메모리 관리, 타입 안정성 및 메모리 정렬 보장이 되지 않는 원시 포인터 액세스를 제공합니다. 이 타입을 사용하려면 누수를 피하고, 할당된 메모리의 라이프 사이클을 직접 관리해야 하며, 그 외의 정의되지 않는 동작들을 회피해야 합니다. 수동으로 직접 관리하는 메모리 영역은 특정한 타입에 바운드되거나, 타입이 지정되지 않을 수도 있습니다. 메모리 영역에서 해당 영역이 특정 타입에 묶여있는지 여부와 무관하게 순수 바이트를 액세스하려할 때 UnsafeRawPointer 타입을 사용할 수 있습니다.

막 할당된 Raw 메모리는 타입화되지도 초기화되지도 않은 상태입니다. 이 메모리는 타입화된 연산을 사용하기 전에 반드시 초기화되어야 합니다. (초기화되려면 초기값을 가져야하고, 이는 타입화를 수반해야한다는 의미가 됩니다.) 초기화되지 않은 상태에서 특정 타입에 바인등하려면 bindMemory(to: count:)를 사용합니다. 이 메소드는 타입화된 포인터를 반환하며, 이후에는 해당 포인터를 사용해야 합니다.

일단 메모리가 특정 타입에 바인드되면, 초기화 여부와 상관없이 해당 포인터는 타입화된 포인터(UnsafePointer/UnsafeMutablePointer)로 액세스됩니다. 초기화, 메모리정렬, 해제와 같은 작업들은 모두 이들 타입화된 포인터의 메소드를 사용하여야 합니다.

특정 타입에 바인드된 메모리를 다른 타입에 리바인드하려면, 이 메모리를 쓸 수 없는 상태로 되돌려지거나(deinitialized), 가리키는 타입이 trivial해야 합니다. (trivial하다는 것은 다른 타입을 간접적으로 참조하지 않는다는 의미입니다.) 초기화를 취소하는 것은 해당 포인터를 사용불가하게 만드는 것일 뿐, 바인드된 타입을 제거하지는 않습니다. 이 상태에서 메모리는 다시 같은 타입으로 초기화될 수도 있고, 다른 타입으로 바인드되거나 해제될 수 있습니다.

특정 타입에 바인드된 후에 해당 포인터로부터 바이트를 읽을 때에는 메모리 정렬과 관련된 요구사항들을 준수해야 합니다.

액세스

가변 포인터는 특정 위치에 값을 쓰는 액션을 허용합니다. 여기에는 복사, 해제 및 초기화동작이 포함됩니다.

생성

불변 포인터는 T타입포인터와 그 호환포인터, 그리고 가변 Raw 포인터등으로부터 인스턴스를 생성할 수 있습니다. 가변포인터의 경우, init(mutating:)을 사용하여 기존 불변포인터로부터 새로운 가변포인터를 생성할 수 있습니다.

가변포인터는 아예 새로운 메모리 공간을 allocate(byteCount:, alignment:)를 사용하여 할당받으면서 생성할 수도 있습니다.

let bytesPointer = UnsafeMutableRawPointer.allocate(
                      byteCount: 4, alignment: 1)
bytesPointer.storeBytes(of: 0xFFFF_0203, as: UInt32.self)
let x = bytesPointer.load(as: UInt8.self) // 3
let offsetPointer = bytesPointer + 2
let y = offsetPointer.load(as: UInt16.self) // 65535

참고로 x86 아키텍처는 리틀 엔디언을 사용하기 때문에, UInt32는 아래쪽 바이트를 먼저 쓴다.

버퍼

바이트의 배열처럼 다룰 수 있게 하는 UnsafeRawBufferPointer 타입도 존재합니다. 각각의 바이트는 1바이트이기 때문에 Int8이나 UInt8 등의 값으로 액세스할 수 있습니다.

Exit mobile version