MISRA C는 자동차 업계가 만든 C 언어 코딩 규칙 모음입니다. 문법상 컴파일은 되지만 사고로 이어지기 쉬운 쓰임새를 막는 게 목적이라, 멀쩡히 돌던 코드에도 경고가 쏟아져요. 규칙은 Mandatory·Required·Advisory 세 등급으로 나뉘어 있어서, 전부 같은 무게로 볼 필요는 없습니다.
먼저 알아둘 용어 (눌러서 펼치기)
| 용어 | 원래 이름 | 쉽게 말하면 |
|---|---|---|
| MISRA C | Motor Industry Software Reliability Association C | 자동차 업계가 만든 “C 언어 안전하게 쓰기” 규칙 모음 |
| 정적 분석 | Static Analysis | 코드를 실행하지 않고 글자만 읽어 문제를 찾는 검사 (맞춤법 검사기처럼) |
| QAC | Perforce QAC (구 Helix QAC) | MISRA 검사에 많이 쓰는 정적 분석 툴 |
| Polyspace | MathWorks Polyspace | MATLAB을 만든 회사의 정적 분석 툴 |
| gcc | GNU Compiler Collection | 무료로 널리 쓰는 C 컴파일러 |
| C 표준 | ISO/IEC 9899 | C 언어의 문법과 계산 규칙을 정한 국제 표준 — C의 헌법 |
| Rule | Rule (MISRA 규칙 항목) | 코드만 읽어도 지켰는지 판단할 수 있는 항목 |
| Directive | Directive (MISRA 지침 항목) | 코드만으로는 판단이 안 돼서 설계 문서·절차까지 봐야 하는 항목 |
| Mandatory | Mandatory (필수) | 예외가 절대 없는 등급 — 공사장 추락 방지 난간 |
| Required | Required (요구) | 원칙상 지키되, 공식 승인(Deviation)이 있으면 예외 가능 — 안전모 |
| Advisory | Advisory (권고) | 권장 사항, 안 지키면 사유를 기록 — 형광 조끼 |
| signed / unsigned | 부호 있는 / 부호 없는 정수 | 마이너스까지 담는 수 / 0부터만 담는 수 (마이너스 칸 없는 눈금자) |
| 암시적 형 변환 | Implicit Conversion | 코드에 안 써도 컴파일러가 규칙대로 몰래 타입을 바꿔 계산하는 것 |
| Deviation | Deviation (규칙 예외 승인) | 근거 문서와 승인을 갖춰 규칙을 공식적으로 예외 처리하는 절차 — 작업 허가서 |
| MCU | Micro Controller Unit | 제품 속에서 기기를 제어하는 작은 컴퓨터 칩 |
| ISO 26262 | Road vehicles — Functional safety | 자동차 전기·전자 장치가 고장 나도 위험하지 않게 만드는 국제 표준 |
MISRA-C란? 양산 전에 꼭 돌리는 C 코딩 규칙
처음 MISRA 리포트를 받아 들었을 때 저는 꽤 당황했습니다. 보드에서 멀쩡히 잘 돌던 코드에 경고가 줄줄이 붙어 있었거든요. “이 업계, 정말 보수적이구나” 싶었죠. 그런데 규칙이 왜 있는지 알고 나니 생각이 조금 달라졌습니다.
MISRA C는 영국 자동차 업계 모임인 MISRA가 1998년에 처음 낸 C 언어 사용 규칙입니다. 공식 표기는 하이픈 없는 MISRA C지만, 현업에서는 MISRA-C라고도 많이 불러요. C는 자유도가 높아서 위험하게 써도 컴파일이 되는 경우가 많습니다. MISRA C는 그런 쓰임새를 골라 “이렇게는 쓰지 말자”고 정해 둔 목록이에요.
검사는 사람이 한 줄씩 읽는 게 아니라 정적 분석 툴이 합니다. 코드를 실행하지 않고 글자만 읽어서 규칙 위반을 찾아내는 방식이라, 맞춤법 검사기가 빨간 줄을 긋는 것과 비슷해요. 자동차 쪽에서는 QAC, Polyspace 같은 툴을 많이 씁니다.
양산 전에 빠짐없이 돌리는 데도 이유가 있습니다. 자동차 기능안전 표준 ISO 26262의 소프트웨어 편(Part 6)은 코딩 가이드라인을 정해 지키라고 요구하고, C 언어의 예로 MISRA C를 듭니다. 그래서 많은 고객이 MISRA 검사 결과 리포트를 함께 요구해요.
컴파일러는 조용한데 틀리는 코드: MISRA C가 막는 함정
말로만 들으면 와닿지 않으니, 컴파일러는 조용한데 실제로는 틀리게 동작하는 코드를 하나 보겠습니다. 온도가 10℃보다 낮으면 히터를 켜는 함수예요.
/* 'u' = unsigned constant */
#define HEATER_ON_LIMIT_C (10u)
/* temp_c is signed: it can be -5 */
bool Heater_ShouldTurnOn(int32_t temp_c)
{
/* MISRA C Rule 10.4 violation */
return (temp_c < HEATER_ON_LIMIT_C);
}
HEATER_ON_LIMIT_C는 히터를 켜는 기준 온도, temp_c는 센서가 읽은 온도(℃)입니다. 이름과 타입은 쓰는 MCU와 프로젝트에 맞게 바꾸면 됩니다.
기준값 끝의 u는 “이 숫자를 unsigned(부호 없는 수)로 다뤄라”라는 표시입니다. 이 u 하나 때문에, 이 함수는 영하에서 히터를 켜지 않아요. 컴퓨터에서 gcc로 직접 돌려 본 결과예요.
| 센서 온도 | 기대한 동작 | 실제 동작 |
|---|---|---|
| −20℃ | ON | OFF ✗ |
| −5℃ | ON | OFF ✗ |
| −1℃ | ON | OFF ✗ |
| 0℃ | ON | ON |
| 9℃ | ON | ON |
| 10℃ | OFF | OFF |
| 25℃ | OFF | OFF |
범인은 암시적 형 변환입니다. C는 signed(부호 있는) 값과 unsigned(부호 없는) 값을 비교할 때, 둘 다 32비트라면 signed 쪽을 unsigned로 바꿔서 계산하도록 정해져 있어요. unsigned는 0부터 시작하는 눈금자라 마이너스 칸이 없습니다. 그래서 −5를 올려놓으면 눈금자 맨 끝으로 넘어가 버려요.
옆으로 밀면 그림 전체를 볼 수 있어요 →
32비트 unsigned 눈금자는 0부터 4,294,967,295(2³² − 1)까지입니다. 그래서 −1은 맨 끝 칸, −5는 끝에서 다섯 번째 칸인 4,294,967,291이 돼요. “4,294,967,291 < 10”은 거짓이니 히터는 꺼진 채로 남습니다. 컴파일러의 실수가 아니라 C 표준에 정해진 규칙 그대로라서, int가 32비트인 MCU라면 어디서든 똑같이 벌어집니다.
더 무서운 건 컴파일러가 조용하다는 점입니다. gcc 13은 C 코드 기준으로 -Wall을 켜도 경고가 없고, -Wextra까지 켜야 알려 줬어요. 게다가 int가 16비트인 MCU에서는 같은 코드가 정상 동작합니다. 그때는 10u가 16비트라서, 더 넓은 int32_t 쪽으로 맞춰 계산되거든요. 같은 코드가 MCU에 따라 맞기도 하고 틀리기도 하는 셈입니다.
MISRA C의 Rule 10.4(Required)는 “연산자 양쪽의 타입 종류를 맞춰라”, 즉 부호 있는 수와 부호 없는 수를 섞어 계산하지 말라는 규칙으로 이런 비교를 아예 막습니다. 그래서 어떤 MCU에서 돌릴 코드든 이 줄을 바로 잡아내요. 고치는 방법도 간단합니다. 기준값을 센서 값과 같은 signed 타입으로 맞추면 됩니다.
/* same signed type as the sensor value */
#define HEATER_ON_LIMIT_C ((int32_t)10)
이렇게 고친 뒤 다시 돌리면 −20℃부터 9℃까지는 ON, 10℃ 이상은 OFF로 기대와 똑같이 동작합니다. MISRA C 규칙 대부분이 이런 함정 앞에 세워 둔 펜스예요. 보수적이라기보다, 빠지기 쉬운 구덩이를 미리 막아 둔 쪽에 가깝습니다.
MISRA C 규칙은 어떻게 생겼나: Rule, Directive, 그리고 3등급
리포트를 열면 Rule 10.4, Dir 4.1 같은 번호가 보입니다. Rule은 코드만 읽어도 지켰는지 판단할 수 있는 규칙이고, Directive는 코드만으로는 판단이 안 돼서 설계 문서나 개발 절차까지 봐야 하는 지침이에요. 그래서 툴 리포트가 0건이라고 끝이 아닙니다. Directive는 툴이 다 볼 수 없으니, 설계 문서와 리뷰로 따로 확인해야 해요. 개수는 2012년판이 처음에 Rule 143개와 Directive 16개였고, 최신판은 합쳐서 220개 안팎입니다.
그렇다고 모든 규칙이 똑같이 무겁지는 않습니다. 규칙마다 등급이 붙어 있고, 등급에 따라 “어겨도 되는지, 어기려면 무엇이 필요한지”가 정해져 있어요. 공사장 안전수칙에 빗대 보면 한눈에 들어옵니다.
옆으로 밀면 그림 전체를 볼 수 있어요 →
Mandatory(필수)는 추락 방지 난간입니다. 어떤 이유로도 예외가 없어서, 위반이 나오면 반드시 고쳐야 해요. Required(요구)는 안전모입니다. 원칙은 꼭 지키는 것이지만, 공식 예외 승인인 Deviation을 받으면 예외가 인정됩니다. Advisory(권고)는 형광 조끼 같은 권장 사항이에요. 공식 승인까지는 필요 없지만, 안 지켰다면 그 사실과 이유를 기록으로 남겨야 합니다. “권고니까 무시해도 된다”가 아니라는 점, 처음에 가장 많이 오해하는 부분입니다.
참고로 정해진 메모리 주소를 직접 건드려야 하는 하드웨어 제어 코드처럼, Rule을 그대로 지키면 오히려 구현이 안 되는 경우도 있습니다. 이럴 때를 위해 Deviation이라는 공식 예외 절차가 있어요. 근거와 승인을 문서로 갖춘 뒤 코드에는 툴이 알아보는 형식의 주석으로 표시하는 방식인데, 주석만 달아서 경고를 끄는 건 인정되지 않는다는 점만 기억해 두면 됩니다.
MISRA C 2012, 2023, 2025: 어떤 판으로 검사할까
판(버전)도 여러 개라 처음엔 헷갈립니다. 현업에서 주로 만나는 세 판을 정리하면 이렇습니다.
| 판 | 발행 | 특징 |
|---|---|---|
| MISRA C:2012 | 2013년 3월 | Directive와 Mandatory 등급이 처음 들어온 판. 가장 오래, 널리 쓰임 |
| MISRA C:2023 | 2023년 4월 | 2012년판과 그 뒤의 개정을 한 권으로 합치고, C 표준의 2011·2018년판까지 지원 |
| MISRA C:2025 | 2025년 3월 | 2023년판을 조금 다듬은 최신판 |
어느 판으로 검사할지는 보통 고객 요구와 프로젝트 계획으로 정합니다. 새 판이 나왔다고 진행 중인 프로젝트가 바로 바뀌지는 않아서, 2012년판으로 검사하는 프로젝트도 여전히 많아요.
현장 팁: 처음 MISRA 리포트를 받았을 때
등급 순서대로 봅니다. Mandatory → Required → Advisory 순서예요. Mandatory는 위반 0건, Required는 0건이거나 남은 위반마다 승인된 Deviation이 있어야 MISRA C를 지켰다고 말할 수 있습니다.
같은 번호끼리 묶어서 봅니다. 매크로나 공통 헤더 한 곳의 문제가, 그걸 쓰는 곳마다 따로 잡혀서 경고 수가 부풀어 있는 경우가 많아요. 원인 한 곳을 고치면 경고 여러 개가 한꺼번에 사라지기도 합니다.
규칙의 “왜”를 읽고 고칩니다. 툴에서 위반 항목을 누르면 규칙 제목과 함께, 왜 위험한지와 예시 코드를 정리한 툴 설명이 나옵니다. 더 정확한 근거는 MISRA C 원문 문서에 규칙마다 적혀 있어요. 이유를 알고 고쳐야 다음 코드에서 같은 위반을 반복하지 않습니다.
막판이 아니라 평소에 돌립니다. 양산 직전에 처음 돌리면 그동안 쌓인 위반이 한꺼번에 쏟아지고, 급하게 고치다 새 버그를 만들기 쉽습니다. 빌드할 때마다, 적어도 릴리스마다 돌려서 위반이 쌓이지 않게 하는 게 좋아요.
MISRA C 자주 묻는 질문
MISRA C를 다 지키면 안전한 소프트웨어인가요?
컴파일러 경고를 전부 켜면 MISRA 검사를 대신할 수 있나요?
Advisory 규칙은 무시해도 되나요?
의도된 설계라서 규칙을 어겨야 하면 어떻게 하나요?
정리
MISRA C는 C 언어의 함정 앞에 세워 둔 펜스입니다. 정적 분석 툴이 규칙 위반을 찾아내고, 자동차 쪽에서는 ISO 26262 같은 기능안전 요구 때문에 양산 전 사실상 필수 검사가 됐어요. 규칙은 Mandatory·Required·Advisory로 무게가 다르고, 어쩔 수 없이 어겨야 할 때는 Deviation이라는 공식 절차가 있습니다.
참고 자료
- MISRA, “MISRA C” 공식 페이지 (판별 발행 이력): https://misra.org.uk/misra-c/
- MISRA, MISRA Compliance:2020 — Achieving compliance with MISRA Coding Guidelines (등급별 처리와 Deviation 절차): misra.org.uk PDF
- ISO 26262-6:2018, Road vehicles — Functional safety — Part 6: Product development at the software level: https://www.iso.org/standard/68388.html
- ISO/IEC 9899:2018 (C17), 6.3.1.8 Usual arithmetic conversions
'임베디드 실무' 카테고리의 다른 글
| 부트로더란? MCU에 부트로더가 필요한 이유와 용도 [초급] (0) | 2026.10.02 |
|---|---|
| 디버거는 어떻게 코드를 한 줄씩 따라갈까 [초급] (0) | 2026.09.29 |
| 폴링 vs 인터럽트, 버튼을 톡 치면 왜 가끔 안 먹을까? [초급] (0) | 2026.09.29 |
| [초급] 풀다운이 더 직관적인데, 스위치엔 왜 풀업 저항을 쓸까? (0) | 2026.09.27 |
| [초급] 차를 세워 뒀을 뿐인데 왜 배터리가 방전될까? 제어기 슬립(Sleep) 모드가 필요한 이유 (0) | 2026.09.26 |
