const는 C 언어에서 객체의 수정 가능성을 제한하는 데 사용됩니다. 함수 매개변수와 작업할 때 이는 데이터가 실수로 변경되는 것을 방지하는 데 도움이 됩니다. 선언의 주요 차이는 const 수정자가 무엇에 적용되는지와 포인터와 관련하여 위치에 따라 달라집니다.
다양한 선언의 예:
void func(const int *ptr); // 상수 int에 대한 포인터 void func(int * const ptr); // 상수 포인터에 대한 int void func(const int * const ptr); // 상수 포인터에 대한 상수 int
const int *ptr — 데이터는 변경할 수 없지만, 포인터는 다시 할당할 수 있습니다.int *const ptr — 데이터는 변경할 수 있지만, 포인터는 다시 할당할 수 없습니다.const int *const ptr — 함수 내에서 데이터나 포인터를 모두 변경할 수 없습니다.const의 올바른 사용: 이는 다음을 가능하게 합니다:
void print_array(const int *arr, size_t n) { for (size_t i = 0; i < n; ++i) { printf("%d\n", arr[i]); // arr[i] = 10; // 오류: const 데이터 변경 시도 } }
질문: 상수 변수가 아닌 포인터에 상수 변수의 주소를 할당할 수 있습니까?
예상되는 잘못된 답변: "예, 포인터의 선언에서 const를 제거하면 컴파일러가 허용합니다."
올바른 답변: 명시적 형 변환(casting)이 있을 때만 "const 하락"이 허용되지만, 이는 const로 선언된 객체를 변경하려고 시도하면 정의되지 않은 동작으로 이어집니다. 이렇게 하면 안 됩니다 — 이는 const의 의미를 위반하며 실행 시간 오류를 초래합니다.
예제:
const int x = 5; int *ptr = (int*)&x; *ptr = 10; // UB: const 객체 변경
이야기
대규모 프로젝트에서 프로그래머가 const 보호를 우회하려 하여 const 포인터를 일반 포인터로 캐스팅하고 읽기 전용 메모리 영역의 데이터를 수정했습니다. 일부 플랫폼에서는 프로그램이 비정상적으로 종료(segmentation fault)되었고, 다른 플랫폼에서는 디버깅하기 어려운 미세한 오류가 발생했습니다.
이야기
배열 작업을 위한 라이브러리에서 개발자가 매개변수를 const로 선언하는 것을 잊었습니다. 이로 인해 부적절한 함수 호출이 우연히 원본 데이터를 변경하여 배열 상태가 비동기화되고 이후 처리 블록에서 심각한 버그가 발생했습니다.
이야기
다른 라이브러리에 전달되는 콜백 함수를 작성할 때 입력 버퍼에 대해 const를 명시하는 것을 잊었습니다. 라이브러리가 상수 문자열의 데이터를 변경하려 했고, 이로 인해 일부 OS에서 충돌이 발생하고 문제의 출처를 파악하기 위한 긴 논의가 이어졌습니다.