숏컷 코드
const 포인터는 결국 “무엇을 못 바꾸는가”를 읽는 문법입니다. 값이 읽기 전용인지, 포인터 자체가 고정인지, 둘 다인지부터 나눠 보면 덜 헷갈립니다.
int value = 10;
const int *p1 = &value;
int *const p2 = &value;
const int *const p3 = &value;문법
const가 포인터 선언에 붙을 때는 가리키는 값 쪽인지, 포인터 변수 쪽인지를 같이 읽어야 합니다.
int value = 10;
int other = 20;
const int *p = &value;
// *p = 30; // ❌ 값 수정 불가
p = &other; // ✅ 다른 대상을 가리키는 건 가능
int *const q = &value;
*q = 30; // ✅ 값 수정 가능
// q = &other; // ❌ 포인터 자체 이동 불가const int *p는 값을 못 바꾸는 포인터이고, int *const p는 포인터 자체가 고정된 변수입니다. const int *const p는 둘 다 못 바꾼다는 뜻입니다.
변경 가능 범위
- 함수 입력이 읽기 전용이면
const T *를 먼저 떠올린다. - 함수가 가리키는 값을 바꾸면 안 되지만 다른 버퍼를 읽을 수는 있어야 할 때
const T *가 맞다. - 포인터 변수 자체를 옮기면 안 되는 지역 변수는
T *const가 맞다. - 둘 다 고정해야 할 때만
const T *const를 쓴다. - 실전에서는 매개변수와 문자열 리터럴에서
const감각이 특히 중요하다.
size_t my_strlen(const char *str);이 선언은 함수가 문자열을 읽기만 한다는 계약을 드러냅니다. 호출자 입장에서도 안전하고, 함수 내부에서 실수로 문자를 바꾸려 하면 컴파일 단계에서 걸리게 됩니다.
문자열 리터럴은 읽기 전용 메모리에 놓일 수 있으므로, char *로 받아 수정하려 들면 위험합니다.
그래서 문자열 입력 API에서는 const char * 감각이 특히 중요합니다.
주의할 점
const를 억지로 떼어내는 캐스팅은 설계 문제를 숨길 뿐입니다. 특히 원본이 실제 상수 메모리라면 매우 위험합니다.
const int VALUE = 42;
int *mutable = (int *)&VALUE;경고를 없애기보다 함수 시그니처를 const에 맞게 고치는 편이 맞습니다.
참고 링크
1 sources