Hungarian 표기법 접두어 해독표 — 변수 이름만 보고 타입·스코프 짐작하기
NOTE
여러 팀이 오래 유지보수하는 통신/임베디드 C 코드베이스에서 여전히 흔히 쓰이는 Hungarian 표기법(변수·타입 접두어로 정보를 이름에 새기는 관례)을 해독하는 방법을 정리한다. 문법이 아니라 네이밍 관례지만, 이걸 모르면 선언부를 안 보고는 변수 이름만으로 아무것도 짐작할 수 없다.
0. 왜 필요한가
Hungarian 표기법을 쓰는 코드는 변수 이름 자체에 타입·스코프 정보를 압축해 넣도록 설계돼 있다. 표기법을 아는 사람에게는 이름만 보고도 선언부를 열어보지 않고 짐작이 가능하다는 게 장점이지만, 표기법 자체를 모르면 정반대로 모든 이름이 암호처럼 보인다. (실무 C 코드 관례와 UB 함정 정리의 A15에서 “팀 컨벤션”으로 짧게 언급한 내용을 여기서 접두어 단위로 풀어서 정리한다.)
1. 자료형 접두어
| 접두어 | 의미 | 예 |
|---|---|---|
n, i | int | n_count, i_idx |
c | char (문자 하나) | c_flag |
sz | 널 종단 문자열(char 배열) | sz_name |
b | bool/on-off 플래그(보통 0 또는 1인 int) | b_enabled |
f | float/double | f_ratio |
u | unsigned (다른 접두어와 조합) | un_count(unsigned int), uc_val(unsigned char), us_port(unsigned short) |
st | 구조체(struct) 인스턴스 | st_msg |
en | 열거형(enum) 값 | en_state |
2. 스코프·형태 접두어
| 접두어 | 의미 | 예 |
|---|---|---|
g | 전역(global) 변수 | g_svcflag |
s | 파일 스코프(static) 변수 | s_cache |
p | 포인터 한 단계 | p_data (= int *p_data처럼 뒤 타입과 조합) |
pp | 포인터의 포인터(두 단계) | pp_list (= char **pp_list) |
| (대문자 시작) | 매크로 상수 / 컴파일 타임 상수 | MAX_RETRY |
3. 접두어는 왼쪽에서 오른쪽으로, “스코프 → 포인터 단계 → 기본 타입” 순으로 조합된다
여러 접두어가 겹친 이름은 한 번에 읽으려 하지 말고, 앞에서부터 한 조각씩 떼어내며 해석한다.
gpst_conn_table
│││└─ conn_table : 의미상 이름 (연결 테이블)
││└── st : 기본 타입 = 구조체(struct) 인스턴스를 가리킴
│└─── p : 포인터 한 단계
└──── g : 스코프 = 전역(global)
→ “전역(g) 포인터(p)가 가리키는 구조체(st) 타입의, 이름이 conn_table인 대상” = st_conn_table_t *gpst_conn_table;에 해당하는 변수라고 짐작할 수 있다. 실제 선언을 찾아 대조해보면 대부분 이 조합 순서(스코프 → 자료형/포인터 단계 → 의미상 이름)를 따른다.
4. 구조체 선언과 타입 정의에서의 관례 (_st_..._t)
변수뿐 아니라 typedef struct를 정의할 때도 일관된 관례가 적용된다:
typedef struct _st_nrf_udr_info_t {
...
} st_nrf_udr_info_t;| 구성 요소 | 의미 | 설명 |
|---|---|---|
st_ / _st_ | Structure | 이 심볼이 구조체임을 나타냄 |
맨 앞 밑줄 _ | 태그명 충돌 방지 | C 문법상 struct 태그명과 typedef 타입명이 네임스페이스를 공유할 때의 이름 충돌을 피하기 위해 태그명 앞에 관례적으로 언더스코어를 붙임 |
nrf_ / sbi_ | 모듈 식별자 | 네임스페이스가 없는 C 언어에서 다른 모듈과의 전역 심볼 충돌을 방지하기 위한 프리픽스 |
_t | Type (자료형) | POSIX 표준(size_t, time_t) 및 C 관례로, typedef로 정의된 사용자 정의 자료형임을 명시 |
5. 함수 이름에서의 관례
- 모듈 접두어: 같은 모듈에 속한 함수는 전부 같은 접두어로 시작해 이름 충돌을 피한다(자세한 내용: A13, 실무 C 코드 관례와 UB 함정 정리). 예:
conn_create,conn_destroy,conn_send처럼conn_이 모듈 경계를 나타낸다. - 동사_명사 순서:
get_config,set_timeout처럼 “무엇을 하는지(동사)“가 앞, “무엇에 대해(명사)“가 뒤에 오는 순서가 흔하다. - 생성/소멸 접미어 쌍:
_init/_destroy,_create/_free같은 이름 쌍이 항상 함께 다닌다는 것 자체가 관례다(실무 C 코드 관례와 UB 함정 정리의 A1).
5. 주의점 — Hungarian 표기법의 한계
- 이름과 실제 타입이 리팩터링 후 어긋날 수 있다 —
n_count로 선언했던 변수를 나중에unsigned int로 바꿔도, 이름의n_접두어까지 자동으로un_으로 바뀌진 않는다. 컴파일러는 이름과 실제 타입의 불일치를 잡아주지 않으므로, 이름은 참고일 뿐 실제 선언부의 타입이 항상 최종 진실이라는 걸 잊으면 안 된다. - 팀마다 접두어의 의미가 다를 수 있다 — 이 표는 통신/임베디드 C 코드베이스에서 흔히 보이는 조합을 정리한 것이지, 모든 프로젝트에 그대로 적용되는 표준은 아니다. 새 코드베이스에 들어가면 기존 코드에서 같은 접두어가 실제로 어떻게 쓰이고 있는지부터 확인하는 게 우선이다.
- 표기법 자체가 3급(팀 컨벤션)이라는 점 — 옳고 그름의 문제가 아니라 “이 팀은 이렇게 쓴다”의 문제다. 최신 오픈소스 트렌드는 IDE의 타입 추론이 좋아지면서 Hungarian 표기법을 지양하는 쪽으로 가고 있지만, 오래 유지보수되는 코드베이스에 새 코드를 추가할 때는 주변 코드의 관례를 따르는 게 일관성 측면에서 낫다.