IAR 컴파일러 경고 해결: undefined behavior : the order of volatile accesses is undefined
임베디드 C 개발을 하다 보면 IAR 컴파일러에서 아래와 같은 경고를 접하는 경우가 있습니다:
Warning[Pa080]: undefined behavior : the order of volatile accesses is undefined in this statement
처음 보는 분들에게는 다소 생소할 수 있지만, 이 경고는 정의되지 않은 동작(undefined behavior) 이 발생할 가능성이 있음을 알려주는 중요한 신호입니다. 이 글에서는 해당 경고의 원인과 해결 방법을 예제와 함께 쉽게 설명드리겠습니다.
🔍 문제 상황 예시
아래는 문제가 되는 코드입니다:
cprintf("a = %d, b = %d\r\nmsec = %d, count = %d\r\n", var_a, var_b, msec, count);
이 코드에서 var_a, var_b, msec, count 중 하나라도 volatile 키워드로 선언되어 있다면, IAR은 위와 같은 경고를 발생시킵니다.
💡 volatile이란?
volatile은 C 언어에서 값이 예측할 수 없이 변경될 수 있는 변수에 사용하는 키워드입니다.
예를 들어, 하드웨어 레지스터, 인터럽트 핸들러에서 변경되는 변수 등이 이에 해당합니다.
volatile int count;
이 변수는 언제 어떤 이유로 값이 바뀔지 모르므로, 컴파일러는 항상 메모리에서 직접 읽고 쓰도록 강제합니다.
⚠️ 경고의 근본 원인
C 언어에서는 함수 인자들의 평가 순서(evaluation order) 가 정의되어 있지 않습니다.
즉, 아래 코드에서:
cprintf("a = %d, b = %d\r\nmsec = %d, count = %d\r\n", var_a, var_b, msec, count);
컴파일러가 var_a, var_b, msec, count를 어떤 순서로 읽을지 보장하지 않으며,
이 변수들이 volatile이면 이는 잠재적인 정의되지 않은 동작이 됩니다.
✅ 안전한 해결 방법
volatile 변수의 값을 임시 변수에 먼저 저장한 뒤, 그 값을 사용하도록 변경하면 경고를 없앨 수 있습니다:
int a = var_a;
int b = var_b;
int t = msec;
int c = count;
cprintf("a = %d, b = %d\r\nmsec = %d, count = %d\r\n", a, b, t, c);
이렇게 하면:
- volatile 변수는 명확한 순서로 한 번씩만 접근되며
- cprintf 함수에는 일반 변수만 전달되므로 경고가 사라집니다.
🧠 추가 설명: C의 평가 순서와 undefined behavior
C 언어는 다음과 같은 경우 평가 순서를 보장하지 않습니다:
- 함수 인자 (func(a(), b()))
- 복합 표현식 (x = y++ + y++)
특히 volatile 변수는 외부에서 변경될 수 있기 때문에, 접근 순서가 중요하며,
컴파일러가 임의로 순서를 바꾸면 잘못된 동작이 발생할 수 있습니다.
💻 실습 예제: IAR에서 volatile 경고 해결
🎯 시나리오
- 2개의 volatile 변수: tick_ms, button_count
- 주기적으로 이 값을 출력하는 코드 작성
- volatile 접근 순서 문제를 해결하는 방식 적용
⚠️ 문제 발생 코드 (비권장 예제)
#include <stdio.h>
volatile int tick_ms = 0;
volatile int button_count = 0;
void show_status() {
// ⚠️ IAR에서는 이 코드에서 평가 순서에 대한 경고가 발생함
printf("tick = %d, button = %d\n", tick_ms, button_count);
}
IAR에서는 아래와 같은 경고 발생:
Warning[Pa080]: undefined behavior : the order of volatile accesses is undefined in this statement
✅ 해결 코드 (권장 예제)
#include <stdio.h>
volatile int tick_ms = 0;
volatile int button_count = 0;
void show_status() {
// 🟢 volatile 변수의 값을 안전하게 임시 변수에 저장
int t = tick_ms;
int b = button_count;
// 🔒 이제 순서와 상관없이 안전하게 출력 가능
printf("tick = %d, button = %d\n", t, b);
}
🧪 테스트 코드 (메인 함수 예시)
int main(void) {
// 초기값 설정 (실제로는 인터럽트나 타이머로 갱신될 수 있음)
tick_ms = 123;
button_count = 7;
// 상태 출력
show_status();
return 0;
}
📎 실제 프로젝트에서의 활용 팁
- volatile 변수는 센서 읽기, 하드웨어 레지스터, 인터럽트와 관련된 데이터에 주로 사용됩니다.
- UI에 표시하거나 로그로 출력할 때는 값을 안정적으로 복사해서 사용하는 습관이 중요합니다.
- 특히 FreeRTOS, CMSIS 같은 실시간 시스템에서는 volatile 변수의 접근을 더욱 신중히 다뤄야 합니다.
✍️ 정리
항목 | 설명 |
문제 | volatile 변수들을 하나의 printf 계열 함수에 동시에 전달할 때 평가 순서 불명확 |
원인 | C 언어는 함수 인자의 평가 순서를 정의하지 않음 |
해결 | volatile 값을 지역 변수에 저장한 후 사용 |
효과 | 정의되지 않은 동작 방지 + 경고 제거 + 코드 안정성 향상 |
'코딩취미 > C,C++' 카테고리의 다른 글
MFC에서 로그 파일 관리: 카테고리 구분 + 자동 파일 분할 기능 구현하기 (0) | 2025.04.07 |
---|---|
C# 코드 정리 방법: 초보자부터 숙련자까지 (SOLID) (0) | 2025.03.02 |
초보자를 위한 C언어 가변 인자 함수: va_list, va_start, va_end 완벽 가이드 (0) | 2024.09.13 |
파일 입출력 초보 탈출! C언어 fopen_s 사용법 정리 (+ fopen 비교) (0) | 2024.09.12 |
InvokeRequired를 사용하는 이유 (사용해야 할 상황 + 사용하면 안되는 상황) (0) | 2024.08.28 |