C 프로그래밍에서 volatile(휘발성) 한정자가 어떤 의미를 가지는지 살펴보겠습니다. volatile 한정자는 변수를 선언할 때 적용하며, 컴파일러에게 해당 변수의 값이 언제든지 변경될 수 있음을 알려주는 역할을 합니다.
volatile의 주요 특징
- volatile 키워드는 메모리 할당을 제거할 수 없습니다.
- 변수를 CPU 레지스터에 캐싱할 수 없습니다.
- 값은 할당 순서대로만 변경됩니다.
그렇다면 volatile 키워드는 어떻게 사용할까요? 다음과 같이 선언하면 됩니다.
volatile int a; int volatile a;
위 두 가지 선언 모두 올바른 방식입니다. 다른 자료형과 마찬가지로 volatile 포인터, 구조체(structure), 공용체(union) 등에도 사용할 수 있습니다. volatile로 선언된 구조체와 공용체는 그 자체로 휘발성을 가질 수 있으며, 내부의 멤버 변수 또한 volatile 타입으로 지정할 수 있습니다.
volatile이 사용되는 경우
volatile은 다양한 상황에서 활용됩니다. 대표적인 사용 사례는 다음과 같습니다.
- 메모리 맵드 주변장치 레지스터: 하드웨어와 직접 통신하는 레지스터
- 전역 변수: 인터럽트 서비스 루틴(ISR)이나 다른 함수에서 접근하는 전역 변수
- 멀티스레드 애플리케이션: 여러 스레드가 동시에 접근하는 변수
예제 코드 비교
int main() {
int value;
value++;
}
int main() {
volatile int value;
value++;
}
위 예제에는 두 개의 코드 블록이 있습니다. 첫 번째 블록에는 volatile 키워드가 없습니다. 이 경우 변수 값이 메모리에서 CPU 레지스터로 복사된 후 연산이 수행됩니다. 반면 두 번째 블록에는 volatile이 선언되어 있으므로, 변수가 메모리에서 레지스터로 복사되지 않고 항상 실제 메모리 위치에서 값을 읽고 쓰게 됩니다.
이러한 차이 때문에 volatile은 컴파일러 최적화로 인해 발생할 수 있는 예기치 않은 동작을 방지하는 데 필수적입니다. 하드웨어 상태 변화나 외부 요인에 의해 값이 변경될 가능성이 있는 변수에는 반드시 volatile을 사용해야 정확한 프로그램 동작을 보장할 수 있습니다.