Swift 속의 C Pointer 이야기 - 시작
Swift 에서 C 포인터(Pointer)는 왜 쓰는가. 모호할 때도 있고 쓰기도 귀찮고 문제도 자주 일으키는 그 개념을 말이다.
그런데 답은 C 포인터 라는 이름에서 이미 나와있다. 당연히 C로 구현된 함수가 포인터를 사용하게 되니 이 함수를 쓰려면 포인터를 다뤄야 한다는 것이다.
C 가 점점 대중(?)들에게 잊혀져 가는 현재로썬 포인터는 거의 쓸 일이 없어졌다고 볼 수도 있다. 하지만 동일개념을 사용하는 C++도 아직 현역이고 암호화 등 바이너리 연산 계통에선 여전히 C가 현역이다. 거기에 포인터도 거의 따라나니다 보니 아직은 땔 수 없는 애증(?)의 관계인 것 같다.
이번 글은 예전에 썼던 포인터 글이 오래된 것 같아 새롭게 Swift 3 기준으로 C 포인터에 대해서 작성해 본다.
대신 Swift 에서는 포인터를 다룰 수 있는 컨테이너를 제공한다.
이런 포인터 컨테이너는 크게 두 부류로 나눌 있다.
그런데 이 중 안전한 포인터는 사실 다룰 여지가 별로 없다. 대표적인 예로 OpaquePointer 같은게 있는데 그냥 정적 포인터이다. C 함수에서 별다른 실수를 하지 않는한 문제를 일으키지 않는다. 심지어 별로 쓸 일 조차 없었다 으어
그렇다면 반대로 위험한 포인터란 무엇인가. 이름에서 풍기는 그 위험함이 꺼림칙하게 만든다. 그런데 사실 많이 위험하지는 않고 그냥 컨테이너 이름이 안안전한(Unsafe)로 시작한다. Dangerous 와 Unsafe 는 확실히 어감이 많이 다르지만 적당한 반대말을 모르겠다. -_-;
Unsafe 류 포인터 컨테이너에는 Swift 의 C 포인터 기능의 거의 모든 내용이 쏠려있다. 그런데 이 녀석도 크게 두 분류로 쪼갤 수 있다.
Swift 의 특징 중 정적 타이핑(Static Typed) 혹은 타입 안전(Type Safe)이 자주 언급된다. 이 말의 의미는 컴파일 타임에 형(type)이 확정되지 않으면 컴파일이 되지 않는다. 그런데 타입이 없는 포인터라는 말은 이 부분에서 모순이 될 지도 모른다.
하지만 C에서 포인터를 다룰 때는 타입이 없는 포인터(void *)를 자주 다룬다. 그 때문인지 이런 형식을 우회적으로 지원하기 위해 타입이 없는 포인터를 특수한 방법으로 지원한다.
약간 더 상세하게 살펴보자.
Mutable 이라는 이름이 붙은 컨테이너의 역활은 어느 정도 유추가 가능할 것이다. 이 녀석은 C 포인터와 함께 따라다니는 Allocation(alloc, malloc, calloc 등) 이나 Deallocation(free 등), Initialization(memset, bzero 등)등의 기능까지 가지고 있어서 광범위한 포인터 혹은 포인터 버퍼 연산을 다룰 수 있다.
자세한 내용은 아래 글을 참고하자:
[상세글] Swift 속의 C Pointer 이야기 - UnsafePointer, UnsafeMutablePointer
C에서 종종 쓰이는
하지만 명확한 타입이 지정되지 않았다는 점 때문에 Swift 에서 생(Raw)포인터를 쓰는 것이 좀 귀찮을 수도 있다.
Mutable 이름이 붙은 것은 위의 타입이 있는 포인터에서 언급했던 것과 비슷하다. 즉 Allocation 과 Deallocation 혹은 메모리 내용 수정 등의 기능을 추가로 더 쓸 수 있다.
자세한 내용은 아래 글을 참고하자:
[상세글] Swift 속의 C Pointer 이야기 - UnsafeRawPointer, UnsafeMutableRawPointer
이 이야기들은 포인터 연산에 관한 것인데 당연히 Swift 의 포인터 컨테이너 들에서도 비슷하게 사용 할 수 있는 것들이다.
물론 컨테이너에 따라 이런 기능들이 필요 없거나 혹은 제공되지 않거나 하기도 하니 절대적인 공통점이라고는 할 수 없다.
[상세글] Swift 속의 C Pointer 이야기 - UnsafeBufferPointer, UnsafeMutableBufferPointer
[상세글] Swift 속의 C Pointer 이야기 - 기타 도구들
그러니 우리 모두 Swift 에서 불안정한 포인터를 써 보고 된통 당해보자. 와~~~ 는 아니고, C와는 다르게 안전장치가 제법 풍부한 편이다 보니 Unsafe 라는 이름에 현혹될 필요는 없을 것 같다.
[관련글] Swift 속의 C Pointer 이야기 - UnsafePointer, UnsafeMutablePointer
[관련글] Swift 속의 C Pointer 이야기 - UnsafeRawPointer, UnsafeMutableRawPointer
[관련글] Swift 속의 C Pointer 이야기 - UnsafeBufferPointer, UnsafeMutableBufferPointer
[관련글] Swift 속의 C Pointer 이야기 - 기타 도구들
[관련글] Swift 와 C 포인터(Pointer) (옛날글)
[관련글] 스위프트(Swift) 가이드
그런데 답은 C 포인터 라는 이름에서 이미 나와있다. 당연히 C로 구현된 함수가 포인터를 사용하게 되니 이 함수를 쓰려면 포인터를 다뤄야 한다는 것이다.
C 가 점점 대중(?)들에게 잊혀져 가는 현재로썬 포인터는 거의 쓸 일이 없어졌다고 볼 수도 있다. 하지만 동일개념을 사용하는 C++도 아직 현역이고 암호화 등 바이너리 연산 계통에선 여전히 C가 현역이다. 거기에 포인터도 거의 따라나니다 보니 아직은 땔 수 없는 애증(?)의 관계인 것 같다.
이번 글은 예전에 썼던 포인터 글이 오래된 것 같아 새롭게 Swift 3 기준으로 C 포인터에 대해서 작성해 본다.
Swift 에서 다루는 포인터의 종류
Swift 라는 언어 자체는 포인터를 지원하지 않는다. 물론 현대적인 언어 답게 레퍼런스 개념을 쓰긴 하지만 레퍼런스는 포인터와는 좀 다르다.대신 Swift 에서는 포인터를 다룰 수 있는 컨테이너를 제공한다.
이런 포인터 컨테이너는 크게 두 부류로 나눌 있다.
- 안전한 포인터
- 위험한(?) 포인터
그런데 이 중 안전한 포인터는 사실 다룰 여지가 별로 없다. 대표적인 예로 OpaquePointer 같은게 있는데 그냥 정적 포인터이다. C 함수에서 별다른 실수를 하지 않는한 문제를 일으키지 않는다. 심지어 별로 쓸 일 조차 없었다 으어
그렇다면 반대로 위험한 포인터란 무엇인가. 이름에서 풍기는 그 위험함이 꺼림칙하게 만든다. 그런데 사실 많이 위험하지는 않고 그냥 컨테이너 이름이 안안전한(Unsafe)로 시작한다. Dangerous 와 Unsafe 는 확실히 어감이 많이 다르지만 적당한 반대말을 모르겠다. -_-;
Unsafe 류 포인터 컨테이너에는 Swift 의 C 포인터 기능의 거의 모든 내용이 쏠려있다. 그런데 이 녀석도 크게 두 분류로 쪼갤 수 있다.
- 타입이 있는 포인터
- 타입이 없는 포인터
Swift 의 특징 중 정적 타이핑(Static Typed) 혹은 타입 안전(Type Safe)이 자주 언급된다. 이 말의 의미는 컴파일 타임에 형(type)이 확정되지 않으면 컴파일이 되지 않는다. 그런데 타입이 없는 포인터라는 말은 이 부분에서 모순이 될 지도 모른다.
하지만 C에서 포인터를 다룰 때는 타입이 없는 포인터(void *)를 자주 다룬다. 그 때문인지 이런 형식을 우회적으로 지원하기 위해 타입이 없는 포인터를 특수한 방법으로 지원한다.
약간 더 상세하게 살펴보자.
타입이 있는 포인터
타입이 있는 포인터 컨테이너는 아래가 대표적이다.- UnsafePointer
- UnsafeMutablePointer
- UnsafePointer<Int>
- UnsafeMutablePointer<Int>
Mutable 이라는 이름이 붙은 컨테이너의 역활은 어느 정도 유추가 가능할 것이다. 이 녀석은 C 포인터와 함께 따라다니는 Allocation(alloc, malloc, calloc 등) 이나 Deallocation(free 등), Initialization(memset, bzero 등)등의 기능까지 가지고 있어서 광범위한 포인터 혹은 포인터 버퍼 연산을 다룰 수 있다.
자세한 내용은 아래 글을 참고하자:
[상세글] Swift 속의 C Pointer 이야기 - UnsafePointer, UnsafeMutablePointer
타입이 없는 포인터
타입이 없는(Untyped) 포인터 컨테이너는 아래가 대표적이다.- UnsafeRawPointer
- UnsafeMutableRawPointer
C에서 종종 쓰이는
void *
즉 무형의 포인터를 안다면 쉽게 이해가 될 것이다. 이 포인터는 char *
로 형변환을 하면 바이트버퍼로 사용 할 수 있게 되고 int *
로 형변환을 하면 정수형 배열처럼 액세스가 가능하다. 물론 이런 행태가 현대적인 언어인 Swift 에서는 이해할 수 없는 행위겠지만 어쨌든 그렇게도 쓸 수 있다.하지만 명확한 타입이 지정되지 않았다는 점 때문에 Swift 에서 생(Raw)포인터를 쓰는 것이 좀 귀찮을 수도 있다.
Mutable 이름이 붙은 것은 위의 타입이 있는 포인터에서 언급했던 것과 비슷하다. 즉 Allocation 과 Deallocation 혹은 메모리 내용 수정 등의 기능을 추가로 더 쓸 수 있다.
자세한 내용은 아래 글을 참고하자:
[상세글] Swift 속의 C Pointer 이야기 - UnsafeRawPointer, UnsafeMutableRawPointer
공통적인 포인터 연산
C 포인터는 메모리 주소(Address)를 가리킨다는 정의가 있다. 해당 주소에는 뭐가 있는지 볼 수 있고 거기다 뭘 넣을 수도 있다. 또한 해당 메모리 주소의 다음 주소나 이전 주소를 탐방하는 것이 가능하다.이 이야기들은 포인터 연산에 관한 것인데 당연히 Swift 의 포인터 컨테이너 들에서도 비슷하게 사용 할 수 있는 것들이다.
- 해당 포인터의 내용 읽기:
let value = pointer.pointee
- 해당 포인터에 내용 쓰기:
pointer.pointee = value
- 해당 포인터의 다음 포인터:
pointer.successor()
- 해당 포인터의 이전 포인터:
pointer.predecessor()
- 해당 포인터의 상대주소 포인터:
pointer.advanced(by: n)
- 해당 포인터의 상대주소의 값 읽기/쓰기:
pointer[n] = value
혹은let value = pointer[n]
물론 컨테이너에 따라 이런 기능들이 필요 없거나 혹은 제공되지 않거나 하기도 하니 절대적인 공통점이라고는 할 수 없다.
기타
직접적인 포인터를 다루는 것은 위의 것이면 충분하겠지만, Swift 에서 포인터를 다루기는 귀찮은 많큼 몇 가지 도구(?)가 제공된다. 아래 글의 링크들을 참고하자.[상세글] Swift 속의 C Pointer 이야기 - UnsafeBufferPointer, UnsafeMutableBufferPointer
[상세글] Swift 속의 C Pointer 이야기 - 기타 도구들
마무리
주로 Unsafe 류에 대한 것을 다루다보니 위험한 상황을 만들지 않을까 걱정되는데, 사실 C 포인터 자체가 원래 안전장치가 부실하다. 남의 메모리에 침범하거나 남의 메모리를 free 시키거나 혹은 free 을 잊어먹거나 등등 다양한 문제를 일으키던 원흉이라 좀 불안정한 것은 사실이다.그러니 우리 모두 Swift 에서 불안정한 포인터를 써 보고 된통 당해보자. 와~~~ 는 아니고, C와는 다르게 안전장치가 제법 풍부한 편이다 보니 Unsafe 라는 이름에 현혹될 필요는 없을 것 같다.
[관련글] Swift 속의 C Pointer 이야기 - UnsafePointer, UnsafeMutablePointer
[관련글] Swift 속의 C Pointer 이야기 - UnsafeRawPointer, UnsafeMutableRawPointer
[관련글] Swift 속의 C Pointer 이야기 - UnsafeBufferPointer, UnsafeMutableBufferPointer
[관련글] Swift 속의 C Pointer 이야기 - 기타 도구들
[관련글] Swift 와 C 포인터(Pointer) (옛날글)
[관련글] 스위프트(Swift) 가이드
댓글