C++ (12) - Const 포인터
본 내용은 어소트락 무료 강의 <C/C++ 무료강의>을 기반으로 공부한 내용을 정리한 것이다. 틀린 내용이 있을 수도 있음.
Keyword : Const
우리는 지금까지 “변수”를 선언해왔다. 그런데 const를 붙이면 변수가 상수화가 된다.
volatile const int cint = 100;
pInt = (int*)&cint;
*pInt = 300;
printf("cint 출력 : %d\n", cint);
상수화 된 값을 “r-value”, 변할 수 있는 값, 변수를 “l-value“라 한다.
cint에 있는 100이라는 값이 절대로 변하지 않는가? No! 강제로 접근이 가능하다.
포인터 개념을 배웠으니 해당 상수의 주소값만 알면 포인터를 이용해 강제로 변경이 가능하다.
volatile은 레지스터 최적화 연산을 통해 상수로 기억된 값이 넘어오지 않도록 하는 기능이다.
레지스터 최적화 : 컴파일러에서 자주 쓰이는 변수를 자동으로 레지스터에 배당함으로써 수행속도를 높이는 최적화 기법.
Const 포인터
포인터에게 있어 상수화는 2가지의 개념이 존재한다.
-
포인터 변수가 가르키는 곳을 바꿀 것인가 말 것인가? (const 포인터)
-
포인터 변수 자체가 상수화가 되어 한번 가르킨 대상에서 더 이상 다른 대상을 가르키지 못할 것인가? (포인터 const)
이는 const 수식어가 붙는 위치에 따라 달라진다.
1. const 와 포인터
const int* pConstInt = &a; // 포인터가 가르키는 원본 쪽(a)을 상수화
*pConstInt = 100; // 포인터가 가르킨 a값이 상수이므로 변경 불가이며 문법오류 발생
int b = 0;
pConstInt = &b; // 다른 주소를 가져와 변경하는 것은 가능하다
정리 : const + 포인터 => 포인터가 가르킨 주소의 값을 고정. 다른 주소를 가져와 변경하는 것은 가능.
2. 포인터 const
int* const pIntConst = &a; // 포인터 변수 자체를 상수화
*pIntConst = 400; // 가르킨 원본(a)값을 변경 가능
pIntConst = &b; // 포인터 변수 자체가 상수화 되었기 때문에 a이외의 다른 값을 가르킬 수 없다.
정리 : 포인터 + const => 포인터 변수 자체를 고정시켜 가르킨 주소만 값을 변경. 다른 주소를 가르킬 수는 없다.
3. 1과2가 합쳐진 경우
const int* const pConsIntConst = nullptr;
// 처음 가르킨 주소와 값을 고정 및 다른 주소 변경조차 불가.
int const* p = &a; // 1. case와 동일하다. *을 기준으로 수식 위치를 보자.
정리 : 초기화 시 가리킨 대상만 가리킴, 가리키는 원본을 수정 할 수 없음.
주의할 점
{
int a = 0;
const int* pInt = &a;
*pInt = 100; // a값 자체가 상수화 (X) / a값에 접근하는 포인터의 기능이 상수화 (제한)
a = 100; // 때문에 이 코드는 오류가 아니다.
int* p = &a; // 다른 포인터를 통해 a값 접근 후 변경이 가능하다.
*p = 100;
}
포인터앞에 const가 붙는 것은 포인터가 가르킨 주소의 값을 상수화 시켜 변경이 불가능하다는 것이 아니다.
해당 포인터가 주소를 가르키며 접근 시 값의 변경 기능에 상수화를 시켜 일종의 제한을 준 기능이다.
따라서 가르킨 주소에 할당된 값은 완전 고정 된 것이 아니라 다른 포인터를 통해 변경이 가능하다.
const 예제 풀이
void Output(const int * pI) // 포인터 앞에 const를 붙혀준다.
{ // 포인터를 통해 접근해서 값이 수정 X
int i = *pI;
*pI = 100; // int 포인터로 강제 캐스팅시 바꿀 수는 있다.
} // 또는 const_cast => 동일한 강제 캐스팅 방법 중 하나
int main()
{
a = 100;
Output(&a); // a값이 조재하는 주소로 포인터를 통해 접근
// 만약 해당 함수에서 자료형이 const로 지정되있지 않으면 함수에 있는 원본 값이 수정되버림.
return 0;
}
함수를 자주 호출하거나 호출 시 필요한 데이터의 양이 너무나도 많거나, 혹은 제작하는 게임 내에서 해당 데이터가 2개 이상 존재하면 안되는 경우 자주 쓰이는 문법이다.
또한 다른 사람과 협업을 할 때 중요하다.
예제의 경우 다른 사람이 만든 void Output함수를 포인터를 통해 값을 가져올 때 내가 만들지 않은 함수 내 원본값 접근 시 원본값의 수정을 방지 하기 위해 const 선언이 반드시 필요하다.
물론 절대적인 것은 없다. (int*) 또는 const_cast 강제 캐스팅을 통해 접근 할 수 있지만 협업하는 사람들과 얼굴 붉히는 일이 없도록 주의해서 사용하자.
그만큼 const 사용은 문법적인 이해도를 높이는 도구라고 할 수 있다.
단축키 : Crtl + Shift + Space = 함수 선언 원형을 알 수 있다. 근데 나는 안보인다.. (VSC 최신판에서는 그냥 함수에 마우스 오버 시 원형 선언 형태가 바로 보인다.)