C 언어에서 포인터는 메모리 모델과 세그먼트 방식에 따라 크게 세 가지 유형으로 분류됩니다.
- 근거리 포인터(Near Pointer)
- 원거리 포인터(Far Pointer)
- 거대 포인터(Huge Pointer)
근거리 포인터(Near Pointer)
- 메모리의 64KB 데이터 세그먼트 범위 안에서만 동작하는 포인터입니다.
- 해당 데이터 세그먼트를 벗어난 주소에는 접근할 수 없습니다.
- 산술 연산자를 이용해 주소 값을 증가시키거나 감소시킬 수 있습니다.
near키워드를 붙이면 어떤 포인터든 근거리 포인터로 만들 수 있습니다.
문법
기본 문법은 다음과 같습니다.
<데이터 타입> near <포인터 정의> <데이터 타입> near <함수 정의>
아래 문장은 변수 s를 가리키는 근거리 포인터를 선언한 것입니다.
char near *string;
예제 프로그램
다음 예제는 근거리 포인터의 사용법을 보여줍니다.
#include <stdio.h>
int main(){
int number = 50;
int near *p;
p = &number;
printf("%d", sizeof(p));
return 0;
}
실행 결과
2
출력 결과가 2바이트인 이유는 근거리 포인터가 세그먼트 내부의 오프셋(offset) 주소만 저장하기 때문입니다. 16비트 환경에서 오프셋은 2바이트로 표현됩니다.
원거리 포인터(Far Pointer)
- 포인터가 가리키는 대상의 세그먼트(segment) 주소와 오프셋(offset) 주소를 모두 저장합니다.
- 전체 16개 세그먼트에 접근할 수 있습니다.
- 주소 표현 범위는 0부터 1MB까지입니다.
- 포인터를 증가 또는 감소시키면 오프셋 부분만 변경됩니다.
문법
<데이터 타입> far <포인터 정의> <데이터 타입> far <함수 정의>
아래 문장은 변수 s를 가리키는 원거리 포인터를 선언한 것입니다.
char far *s;
예제 프로그램
#include <stdio.h>
int main(){
int number = 50;
int far *p;
p = &number;
printf("%d", sizeof(p));
return 0;
}
실행 결과
4
출력 결과가 4바이트인 이유는 원거리 포인터가 세그먼트 주소(2바이트)와 오프셋 주소(2바이트)를 함께 저장하기 때문입니다.
거대 포인터(Huge Pointer)
- 크기 면에서 원거리 포인터와 동일하게 32비트 주소를 사용합니다.
- 세그먼트 경계 넘어감(wrap-around) 문제 없이 증감 연산이 가능합니다.
거대 포인터는 증감 연산 시 세그먼트 값까지 자동으로 조정해 주므로 1MB 전체 메모리를 연속적으로 순회할 수 있습니다. 반면 원거리 포인터는 오프셋만 변경되므로 세그먼트 경계를 넘어 접근할 수 없다는 점이 가장 큰 차이입니다.
예제 프로그램
#include <stdio.h>
int main(){
char huge **ptr;
printf("%d %d %d", sizeof(ptr), sizeof(*ptr), sizeof(**ptr));
return 0;
}
실행 결과
4 4 1
ptr 자체는 32비트(4바이트) 거대 포인터이고, *ptr 역시 4바이트 크기의 거대 포인터이며, **ptr은 실제 문자(char) 데이터이므로 1바이트입니다.
정리
근거리·원거리·거대 포인터는 16비트 x86 환경(DOS 시대)의 세그먼트:오프셋 메모리 구조에서 사용되던 개념입니다. 현대의 32비트·64비트 시스템은 플랫(flat) 메모리 모델을 사용하기 때문에 이러한 구분이 필요 없지만, 레거시 코드나 임베디드 시스템을 다룰 때는 여전히 알아두어야 할 중요한 개념입니다.