포인터
소개
이 문서는 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의 안전한 컴파일러 구조 덕분에 포인터 사용 중 발생할 수 있는 위험 요소들을 효과적으로 방지할 수 있습니다.