Computer >> 컴퓨터 >  >> 프로그래밍 >> C 프로그래밍

C 언어의 근거리(Near)·원거리(Far)·거대(Huge) 포인터 완벽 정리

C 언어에서 포인터(pointer)는 메모리 주소를 저장하는 변수로, 프로그램이 데이터에 직접 접근할 수 있게 해주는 핵심 개념입니다. 특히 16비트 도스(DOS) 시절의 x86 아키텍처에서는 메모리를 세그먼트(segment) 단위로 나누어 관리했기 때문에, 포인터의 종류에 따라 접근할 수 있는 메모리 범위가 달라졌습니다. 이때 사용된 것이 바로 근거리(Near), 원거리(Far), 거대(Huge) 포인터입니다.

1. 근거리 포인터(Near Pointer)

근거리 포인터는 16비트 크기의 주소만 저장하는 포인터입니다. 하나의 세그먼트(최대 64KB) 내부에 있는 데이터에만 접근할 수 있으며, 세그먼트 정보를 별도로 저장하지 않고 오프셋(offset) 값만 가집니다.

가장 큰 단점은 접근 가능한 메모리 범위가 약 64KB로 제한된다는 점입니다. 즉, 현재 세그먼트를 벗어난 영역의 데이터에는 전혀 접근할 수 없습니다. 대신 구조가 단순하고 속도가 빠르다는 장점이 있습니다.

2. 원거리 포인터(Far Pointer)

원거리 포인터는 32비트 크기를 가지며, 세그먼트 주소와 오프셋 주소를 함께 저장합니다. 덕분에 현재 세그먼트 외부에 있는 메모리 영역에도 접근할 수 있습니다.

사용하려면 세그먼트 레지스터에 해당 데이터가 위치한 세그먼트 주소를 지정해야 하며, 필요에 따라 다른 세그먼트 레지스터에 최근 세그먼트 정보를 유지해야 합니다. 근거리 포인터보다 넓은 메모리를 다룰 수 있지만, 매번 세그먼트를 명시적으로 관리해야 하므로 처리 과정이 상대적으로 복잡합니다.

3. 거대 포인터(Huge Pointer)

거대 포인터 역시 원거리 포인터처럼 32비트 크기를 가지며, 세그먼트 외부의 메모리에 접근할 수 있습니다. 두 포인터의 결정적인 차이는 주소 정규화(normalization) 여부입니다.

원거리 포인터는 한 번 설정된 세그먼트 값이 고정되어 있어, 해당 세그먼트 내부의 위치를 임의로 변경하거나 조정할 수 없습니다. 반면 거대 포인터는 주소를 항상 표준 형태로 정규화하기 때문에, 세그먼트 경계를 넘어서는 연산(예: 64KB를 초과하는 배열 순회)도 올바르게 수행할 수 있습니다. 이로 인해 거대 포인터는 산술 연산 결과가 항상 일관되게 유지되지만, 정규화 과정 때문에 실행 속도는 다소 느려집니다.

세 가지 포인터 비교 요약

  • 근거리 포인터: 16비트, 세그먼트 내 64KB까지만 접근 가능, 빠르고 단순함
  • 원거리 포인터: 32비트, 세그먼트 외부 접근 가능, 세그먼트 값 고정
  • 거대 포인터: 32비트, 세그먼트 외부 접근 가능 + 주소 정규화 지원, 느리지만 안정적

참고로 이러한 포인터 구분은 16비트 세그먼테이션 방식을 사용하던 도스·터보 C(Turbo C) 시대의 유산입니다. 현대의 32비트·64비트 운영체제에서는 플랫(flat) 메모리 모델을 사용하기 때문에 이러한 구분이 사라졌으며, 모든 포인터가 동일하게 전체 메모리 공간을 다룹니다. 다만 레거시 코드나 임베디드 환경을 다룰 때는 여전히 중요한 개념이므로, 그 동작 원리를 이해해 두면 큰 도움이 됩니다.