포인터의 크기와 데이터 타입
포인터의 크기와 데이터 타입
Understanding and Using C Pointers: Core Techniques for Memory Management 1st Edition을 읽고 정리한 내용을 기술합니다.
Understanding and Using C Pointers 정리 시리즈
포인터 크기
포인터의 크기는 애플리케이션의 호환성과 다른 환경으로의 이식 가능성을 고민할 때 문제가 된다.
최근의 대부분의 OS에서 포인터의 크기는 일반적으로 포인터 타입에 상관없이 같다.
예를 들면, char에 대한 포인터(char*)는 구조체에 대한 포인터와 크기가 같다!
C 표준에서 모든 데이터 타입에 대한 포인터의 크기가 같아야 한다고 명시하고 있지만 않지만, 일반적으로 포인터의 크기는 동일하다. 하지만 함수에 대한 포인터와 데이터에 대한 포인터의 크기는 다를 수도 있다.
C는 코드와 데이터 포인터 크기가 다른 Harvard 아키텍처를 선호하지 않는다고 한다.
-> 이는 강제적인 규칙이 아닌 편리성과 이식성을 고려한 결과임.
-> 하버드 구조에서는 코드와 데이터가 다른 크기를 가질 수 있음.
참조 : 폰노이만 구조와 하버드 구조
메모리 모델
이전 포스팅의 C++11 메모리 모델과는 이름만 같고 다른 개념임.
C++11에서의 메모리 모델은 원자적 연산, 메모리 순서 등에 대한 기능의 도입과 관련된 것들을 의미함.
이번 포스팅에서의 C 메모리 모델은 각 데이터 타입에 관한 것들임.
64비트 컴퓨터의 도입으로 C 기본 데이터 타입의 메모리 크기 차이가 더 확실해졌다. 컴퓨터와 컴파일러들은 C 기본 데이터 타입의 메모리 할당을 위해 저마다 다른 옵션의 메모리 모델을 가지고 있다. 이 메모리 모델들을 설명하기 위해 일반적으로 아래와 같은 표기법을 사용한다.
I In L Ln LL LLn P Pn
각 대문자는 정수(Integer), 롱(Long), 포인터(Pointer)에 해당하며, 각 소문자는 타입에 할당된 비트 수다. 아래 표는 이러한 메모리 모델을 정리한 것이며, 표 안의 숫자는 비트 수를 나타낸다.
Datatype | LP64 | ILP64 | LLP64 | ILP32 | LP32 |
---|---|---|---|---|---|
char | 8 | 8 | 8 | 8 | 8 |
short | 16 | 16 | 16 | 16 | 16 |
int | 32 | 64 | 32 | 32 | 16 |
long | 64 | 64 | 32 | 32 | 32 |
long long | 64 | ||||
pointer | 64 | 64 | 64 | 32 | 32 |
long long
타입은 컴파일러에 따라 지원하지 않을 수도 있다.
메모리 모델은 운영체제와 컴파일러에 따라 다르다. 운영체제들은 하나 이상의 메모리 모델을 지원하며, 각 메모리 모델은 컴파일러 옵션에 따라 제어된다.
사전 정의된 포인터 관련 데이터 타입
포인터를 다룰 때, 다음 네 가지의 사전 정의된(Predefined) 데이터 타입이 종종 사용된다.
size_t
: 안전한 크기 타입 제공을 위해 사용ptrdiff_t
: 포인터 연산을 처리하기 위해 사용intptr_t
,uintptr_t
: 포인터 주소를 저장하기 위해 사용
size_t
// vcruntime.h 에 정의됨
#ifdef _WIN64
typedef unsigned __int64 size_t;
#else
typedef unsigned int size_t;
#endif
size_t
타입은 C언어에서 임의의 객체가 가질 수 있는 최대 크기를 나타낸다. 크기를 표현하는 데 음수의 사용은 의미가 없기 때문에 size_t
는 부호 없는 정수를 사용한다.
size_t
타입을 쓰는 이유는 시스템에서 주소 지정이 가능한 메모리 영역과 일치하는 크기를 선언하는 이식 가능한 방법을 제공하기 위해서다.
size_t
타입은 sizeof
연산자의 반환 타입으로 사용되며 많은 함수들의 인자로도 사용된다. malloc
함수와 strlen
함수가 size_t
타입을 반환하거나 인자로 사용하는 대표적인 함수다.
strlen
size_t strlen(const char *str)
문자의 수나 배열 인덱스와 같은 크기 변수를 선언할 때는 size_t 타입을 사용하는 것이 좋다.
size_t
타입의 형식 지정자로는 %zu
지정자를 사용한다. 해당 지정자가 지원되지 않는 경우 대안으로 %u
또는 %lu
지정자를 사용할 수 있다.
intptr_t와 uintptr_t
intptr_t
와 uintptr_t
타입은 포인터의 주소를 저장하는 데 사용된다. 이 두 타입은 다른 환경으로 이식이 가능하고 안전한 포인터 선언 방법을 제공하며, 시스템 내부에서 사용하는 포인터와 같은 크기다.
사용 방법
int num;
intptr_t *pi = #
uintptr_t *pu = (uintptr_t*)# // uintptr_t의 경우 타입 캐스팅을 해주어야 한다.
ptrdiff_t
ptrdiff_t
타입은 두 포인터의 차를 표현하기 위한 이식성 있는 방법을 제공한다. 포인터의 크기는 다를 수 있기 때문에 ptrdiff_t
타입을 사용하면 포인터의 차를 다루는 일을 간소화 할 수 있다.