형 한정자는 변수의 사용을 제한하기 위해 사용해요. 기억영역 클래스 뒤와 자료형 앞에 사용해요.
const 형 한정자를 사용한 변수는 초기화는 가능하지만, 그 후에 새 값을 할당하거나 증가, 감소, 수정될 수 없어요.
const double pi = 3.14;
pi = 3.141592; // 앞서 초기화되었기 때문에 값을 수정할 수 없어요.
const 변수라 하더라도, 포인터를 사용해 값을 변경할 수 있어요.
const int answer = 10;
int *p = &answer; // 컴파일러가 경고해줘요.
*p = 42;
printf("answer = %d\n", answer); // 42
위 코드를 컴파일하면, 포인터 변수 p를 초기화 하는 부분을 컴파일러가 경고해줘요.
위 코드를 실행해보면, answer의 결과가 10이 아닌 42로 포인터에 의해 변경된 것을 볼 수 있어요.
그렇다면, const 변수를 안전하게 포인트 하려면 어떻게 해야 할까요?
포인터 변수를 const로 만들어 해결할 수 있어요.
const int answer = 10;
const int *p = &answer;
*p = 42; // 오류 발생
const로 선언한 포인터 변수 p 자체는 상수가 아니지만, p에 역참조 연산자를 사용해 원본을 변경할 수 없어요.
C99에 추가된 restrict 형 한정자는 포인터 변수에 사용할 수 있어요.
restrict를 사용하면, 현재 포인트 되는 객체는 다른 포인터에 의해서는 포인트 되지 않음을 명시할 수 있어요. restrict 형 한정자는 컴파일러가 코드 최적화를 수행하는데 도움을 줘요.
아래 코드는 두 int형 포인터를 인자로 받는 swap_int 함수에요.
void swap_int(int *a, int *b)
{
int tmp = *a;
*a = *b;
*b = tmp;
}
두 메모리 주소에 저장된 값을 바꾸는 함수이니, 같은 주소의 경우는 바꿀 필요가 없어요. 따라서, 명시적으로 각각 다른 주소임을 restrict를 사용해 명시할 수 있어요.
int swap_int(int * restrict a, int * restrict b)
{
if (a == b) return EOF;
int tmp = *a;
*a = *b;
*b = tmp;
}
restrict 형 한정자를 적용해서, 컴파일러에서 최적화가 이루어지는걸 어셈블리 등으로 확인할 수 있는 사례를 찾고있어요! 혹시나 좋은 사례가 있다면, 댓글로 공유해주세요 😉
배운 내용들을 정리해보고 있어요. 잘못 기재된 내용이 있다면, 댓글로 지적해주시면 수정할게요.