Перейти к основному содержимому

포인터

소개

이 문서는 Wave의 포인터 활용 방식에 관하여 설명하는 문서입니다. Wave는 저수준 시스템 프로그래밍을 지원하는 언어로서, 명시적인 메모리 주소 조작을 가능하게 하기 위해 포인터 기능을 제공합니다. 포인터는 특정 타입의 메모리 주소를 가리키는 변수이며, 이를 통해 값에 대한 직접적인 접근 및 수정이 가능합니다.


포인터 선언

Wave에서 포인터는 ptr<타입> 형식으로 선언합니다. 예를 들어, 정수형 포인터는 다음과 같이 선언할 수 있습니다:

var p: ptr<i32>;

이 선언은 i32 타입 값을 가리키는 포인터 p를 생성합니다.


포인터 초기화

포인터는 변수의 주소를 & 연산자를 사용하여 초기화할 수 있습니다:

var a: i32 = 10;
var p: ptr<i32> = &a;

여기서 &a는 변수 a의 메모리 주소를 의미하며, p는 해당 주소를 가리키는 포인터가 됩니다.


포인터 역참조

포인터가 가리키는 값을 읽거나 수정하려면 deref 키워드를 사용합니다. 이를 역참조라고 합니다:

var a: i32 = 10;
var p: ptr<i32> = &a;

println("{}", deref p); // 10 출력

deref p = 20;
println("{}", a); // 20 출력

NULL 포인터

Wave에서는 널 포인터를 null 키워드를 통해 표현합니다. 포인터 변수는 null로 초기화될 수 있스며, 이 경우 어떤 유효한 메모리도 가리키지 않습니다:

var p: ptr<i32> = null;

널 포인터를 역참조할 경우 컴파일러는 오류를 발생시킵니다.


다중 포인터

Wave는 다중 포인터를 지원합니다. 포인터를 여러 단계로 중첩하여 선언하고 사용할 수 있습니다:

var x: i32 = 1;
var p1: ptr<i32> = &x;
var p2: ptr<ptr<i32>> = &p1;
var p3: ptr<ptr<ptr<i32>>> = &p2;

println("{}", deref p1); // 1
println("{}", deref deref p2); // 1
println("{}", deref deref deref p3); // 1

배열과 포인터

포인터는 배열 요소 또는 배열 자체를 가리킬 수도 있습니다.

배열 요소를 가리키는 포인터

var a: i32 = 10;
var b: i32 = 20;
var arr: array<ptr<i32>, 2> = [&a, &b];

println("deref arr[0] = {}, deref arr[1] = {}", deref arr[0], deref arr[1]); // 10, 20

배열 전체를 가리키는 포인터

var arr: ptr<array<i32, 3>> = &[1, 2, 3];
println("{}", arr); // 메모리 주소 출력

안전성과 소유권

Wave는 Rust와 유사한 방식으 소유권 및 수명 시스템을 도입하여 포인터 사용시 메모리 안정성을 보장하려고 합니다. 따라서 유효하지 않은 포인터 역참조, 이중 해제, 댕글링 포인터 등의 문제가 발생하지 않도록 철저히 검사합니다.

fun main() {
let x: i32 = 42;
let p: ptr<i32> = &x;

println("x = {}", deref p);

deref p = 99;
println("x = {}", x);
}

출력:

x = 42
x = 99

결론

포인터는 Wave에서 고성능 저수준 프로그래밍을 가능하게 하는 핵심 기능 중 하나입니다. 직접적인 메모리 제어가 필요한 시스템 개발, 네이티브 라이브러리, 하드웨어 제어 등에 매우 유용하며, Wave의 안전한 컴파일러 구조 덕분에 포인터 사용 중 발생할 수 있는 위험 요소들을 효과적으로 방지할 수 있습니다.