-
13장 저수준 프로그래밍카테고리 없음 2019. 11. 25. 21:50
The Go Programming language
개요
unsafe 패키지를 사용해 일반적인 규칙에서 벗어나는 방법과 cgo 도구를 통해 C 라이브러리와 운영체제 호출을 위한 Go 바인딩을 생성하는 방법을 알아본다.
unsafe 패키지는 runtime, os, syscall, net 등 운영체제와 상호작용하는 저수준 패키지에서 광범위하게 사용된다.
13.1 unsafe.Sizeof Alignof, Offsetof
unsafe.Sizeof 함수는 모든 타입 표현식의 피연산자를 바이트로 표현한 크기를 보고한다.
표현식 자체는 평가되지 않는다. Sizeof 호출은 unitptr 타입의 상수 표현식이므로 그 결과는 배열 타입의 차원이나 다른 상수 계산식으로 사용할 수 있다.
import "unsafe" fmt.Println(unsafe.Sizeof(float64(0))) // "8"
unsafe.Alignof 함수는 인자 타입에 필요한 정렬 방식을 알려준다.
Sizeof와 마찬가지로 모든 타입의 표현식에 적용할 수 있으며 상수를 산출한다.
일반적으로 분리언과 숫자 타입은 그 크기(최대 8바이트)로 정렬되고 그 외의 타입들은 워드로 정렬된다.
피연산자가 필드 셀렉터 x.f인 unsafe.Offsetof 함수는 바깥쪽 구조체 x의 시작 위치에서 상대적인 필드 f의 오프셋을 계산하며 홀(hole)이 있다면 홀로 포함된다. 홀은 컴파일러에 의해 추가되고 사용되지 않은 공간으로 이후의 필드나 원소가 구조체 또는 집합의 시작 위치에서부터 적절하게 정렬되게 한다.
var x struct { a bool b int16 c []int }
다음 표는 3가지 unsafe 함수를 x와 x의 세 필드들에 적용된 결과이다.
Typical 32-bit platform: Sizeof(x) = 16 Alignof(x) = 4 Sizeof(x.a) = 1 Alignof(x.a) = 1 Offsetof(x.a) = 0 Sizeof(x.b) = 2 Alignof(x.b) = 2 Offsetof(x.b) = 2 Sizeof(x.c) = 12 Alignof(x.c) = 4 Offsetof(x.c) = 4 Typical 64-bit platform: Sizeof(x) = 32 Alignof(x) = 8 Sizeof(x.a) = 1 Alignof(x.a) = 1 Offsetof(x.a) = 0 Sizeof(x.b) = 2 Alignof(x.b) = 2 Offsetof(x.b) = 2 Sizeof(x.c) = 24 Alignof(x.c) = 8 Offsetof(x.c) = 8
다음은 구조체 변수 x와 일반적인 32비트와 64비트 Go 구현에서 변수 x의 메모리 배치를 보여준다. 회색 영역은 홀이다.
13.2 unsafe.Pointer
대부분의 포인터 타입은 *T로 작성하며 "타입 T의 변수에 대한 포이터"를 의미한다.
unsafe.Pointer 타입은 모든 변수의 주소를 저장할 수 있는 특별한 종류의 포인터이다.
unsafe.Pointer 타입은 일반 포인터처럼 타입의 제로 값인 nil과 비교할 수 있다.
일반적인 *T 포인터는 unsafe.Pointer로 변환할 수 있고 unsafe.Pointer는 다시 일반 포인터로 변환할 수 있으며 이때 같은 *T 타입일 필요는 없다. unsafe.Pointer 변환은 임의 값을 메모리에 기록해서 타입 시스템을 파괴할 수 있다.
unsafe.Pointer를 포인터의 숫자 값을 갖는 uintptr로 변환해 주소에 대해 산술 연산을 수행할 수 있다. 이 변환도 역으로 수행할 수 있지만 uintptr에서 unsafe.Pointer로의 변환도 모든 숫자가 유효한 주소는 아니기 때문에 타입 시스템을 파괴할 수 있다.
일부 가비지 컬렉터는 조각을 줄이거나 기록하기 위해 메모리상의 변수를 이동시킨다. 이런 종류의 가비지 컬렉터를 이동 GC(moving GC)라 한다.
모든 uintptr 값이 변수의 이전 주소를 갖는다고 가정하고 unsafe.Pointer에서 uintptr로의 변환과 uintptr 사용 횟수를 최소한으로 유지하라.
13.3 예제: 깊은 동등성
reflect 패키지는 DeepEqual 함수는 두 값이 "깊게" 같은지 여부를 보고한다.
13.4 cgo를 통한 C 코드 호출
C 함수의 Go 바인딩을 생성하는 cgo 도구를 외부 함수 인터페이스(FFI, foreign-function interface)라 하며 Go 프로그램에는 cgo 외에도 여러 가지 도구가 있다. SWIG(swig.org)도 그중 하나다.
13.5 기타 주의 사항
세심한 연구와 측정 결과에 의해 unsafe가 가장 좋은 접근이라고 판단되면 가급적 제한된 작은 영역에만 사용해야 하며 대부분의 프로그램에서 그 사용에 대해 고려하지 않게 해야 한다.