mir.pe (일반/밝은 화면)
최근 수정 시각 : 2024-10-09 15:05:17

헝가리안 표기법

파일:관련 문서 아이콘.svg   관련 문서: 코딩 스타일
,
,
,
,
,

1. 개요2. 적용하기
2.1. Systems Notation
2.1.1. 공통2.1.2. OOP2.1.3. Windows API
2.2. Apps Notation
2.2.1. 예시
3. 장점4. 단점5. 몰락과 유산6. 관련 문서

1. 개요

프로그래밍 언어에서 변수 및 함수의 인자 이름 앞에 데이터 타입을 명시하는 코딩 규칙이다.

찰스 시모니(Charles Simonyi) 가 마이크로소프트의 개발 책임자로 있을 때 제안했으며, 80년대 당시에는 IDE라는게 다들 부실했기 때문에 이 규칙이 엄청난 센세이션을 불러 일으켰다. 하지만 지금은 MS도 공식 가이드라인에서 사용하지 말 것을 권고[1]하고 있다.

헝가리안 표기법이라는 명칭은 제안자인 찰스 시모니가 헝가리인이라서 붙은 것이다.

2. 적용하기

아래 표만 잘 기억하면 된다.
물론 이렇게 정해야 한다는 명확한 룰 자체가 없으므로, 사용자나 이를 설명한 사이트에 따라 조금씩 다를 수는 있다.

2.1. Systems Notation

데이터의 타입을 명시하는 방식으로, 널리 알려진 방식이다. 이런 방식 자체는 6,70년대 C언어 이전 타입시스템이 없는 언어에서 변수명에 변수의 타입을 명시해서 사용한 것이 시초이다.

2.1.1. 공통

접두어 데이터 타입
b byte, boolean
n int, short
i int, short (주로 인덱스로 사용)
c int, short (주로 크기로 사용)
l long
f float
d, db double
ld long double
w word
dw double word
qw quad word
ch char
sz NULL로 끝나는 문자열
str C++ 문자열
arr 배열 (문자열 제외): 다른 접두어와 조합 가능
p 포인터 (16비트, 32비트): 다른 접두어와 조합 가능
lp 포인터 (32비트, 64비트): 다른 접두어와 조합 가능
psz NULL로 끝나는 문자열을 가리키는 포인터 (16비트, 32비트)
lpsz NULL로 끝나는 문자열을 가리키는 포인터 (32비트[2], 64비트)
fn 함수 타입
pfn 함수 포인터 (16비트, 32비트)
lpfn 함수 포인터 (64비트)

2.1.2. OOP

접두어 데이터 타입
g_ 네임스페이스의 글로벌 변수
m_ 클래스의 멤버 변수
s_ 클래스의 static 변수
c_ 함수의 static 변수
다른 타입 접두어 앞에 붙인다. (예: m_lpszName - 클래스 멤버 변수인 문자열 포인터)
이 접두어들은 당연히 private 멤버에 사용하는 것이다. 절대 public으로 오픈하지 말 것.

2.1.3. Windows API

접두어 데이터 타입
h 리소스 핸들 (HWND를 제외한 모든 HANDLE 타입)

Windows API 문서를 보면 wParamlParam이 지겹게 등장하는데, 접두어대로 wParam은 word나 dword 기반, lParam은 int나 long 기반이다.

2.2. Apps Notation

데이터 타입이 아닌, 데이터의 논리적 상태를 명시하는 방식이다. 변수 뿐 아니라 함수에도 사용가능하다.

사실상 이쪽이 시모니가 의도한 진짜 사용법이라고 볼 수 있다. <조엘 온 소프트웨어>로 유명한 조엘 스폴스키도 블로그에서 이러한 점을 지적하며 잘 작성된 헝가리안 표기법을 사용하면 코드에서 "버그가 스스로 드러나는" 코딩을 할 수 있다고 주장했다. #영어 의미에 따라 접두어가 붙기 때문에 의도치 않은 대입 등을 바로 알 수 있기 때문이다.

시모니가 MS에서 작성한 헝가리안 표기법 제안을 봐도 단순히 기계적으로 타입명을 붙이라고는 하지 않았다. 접두사 ch에 대한 설명을 보면 "char형. 일반적으로 아스키 문자"라고 되어 있다. 즉, "ch가 붙은 변수는 문자라는 '의미'이므로 문자 말고 다른 값이 들어가지 않도록[3] 주의하며 코딩해라"라는 의미.

2.2.1. 예시

타입이 아니라 의미에 따라 이름을 붙이는 방법이기 때문에 정해진 규칙이 없다. 이런점이 Apps Notation을 배우기 어렵게 하고 Systems Notation이 대세가 된 이유이기도 하다.
접두어 의미
n Count 변수
d 두 값의 차이를 담는 변수
us 안전이 확인되지 않은 변수(UnSafe).[4]
s 안전이 확인된 변수(Safe)
Locked 함수의 접미사. 스레드 안전하지 않은 함수기 때문에 사용하기 전에 Lock을 잡아야 한다 안드로이드에서 사용된다.

간단히 예를들면
#!syntax java
int sValue = usValue; // Unsafe 값을 Safe 변수에 바로 넣었다. 양변의 의미가 다르므로 문제가 있는 코드

sValue = sCheck(usValue); // us값을 체크해서 s로 바꿔주는 함수 sCheck를 거쳤다. 양변이 모두 s이므로 문제없는 코드

sValue = sCheckLocked(usValue); // 의미는 맞지만 Locked 함수를 쓰기 전에 락을 걸지 않았다. 멀티스레드에서 동작시 문제가 생길 수 있다.

3. 장점

4. 단점

5. 몰락과 유산


IDE의 눈부신 발전 덕분에 헝가리안 표기법은 단숨에 구식으로 변하고 말았다. 최신 IDE에서는 마우스 커서만 올리면 심볼의 데이터 타입은 물론 선언 및 참조 위치까지도 한 눈에 확인할 수 있다. IDE가 제공하는 타입 분석 기능이 너무나 강력한 바람에, 심지어는 후대에 나온 동적 타입 언어들까지도 정적 타입 비슷한 기능을 붙여서 IDE의 기능을 최대한 뽑아내려고 할 정도다.

상술한 이유로 대부분의 최신 개발 환경에서는 헝가리안 표기법이 나쁜 습관으로 간주된다. 특히 map/set/array(list) 등 자료형의 이름을 심볼 이름으로 쓰는 습관은 반드시 고치는 게 좋다. cardList보다는 cards가 더 좋고, 여기에 논리적인 응집이 더 필요하면 Deck이라는 클래스를 만드는 식으로 생각해야 한다.

다만, 데이터의 논리적인 상태를 나타내는 Apps Notation과 유사한 관습은 지금도 간간히 남아있다.

이런 의미론적인 표기법은 IDE가 직접 지원하기도 한다. 최신 IDE에서 특정한 정규표현식(예: 맨 앞에 '_')을 만족하는 심볼에 대해 특정 코드 검사(예: 안 쓰는 변수)를 비활성화하는 옵션 등을 비교적 쉽게 찾아볼 수 있다.

6. 관련 문서



[1] https://msdn.microsoft.com/en-us/library/ms229045(v=vs.100).aspx 내용 자체는 .NET Framework에 적용되는 문서이긴 하지만 새로 만드는 SDK의 API들은 헝가리안 표기법에서 탈피하고 있다. [2] 윈도우즈 API에서 아주 많이 쓰인다. 함수의 파라미터 중에 문자열은 LPCTSTR lpName 식의 표기가 대부분이다. [3] C언어에서는 문자도 그냥 1바이트 정수로 취급하므로 숫자를 대입해도 아무 이상이 없다. [4] 사용자 입력값을 그대로 받아서 무결성 검증이 되지 않았고(나이에 음수를 넣었다거나), SQL injection처럼 해킹의 의도를 가진 문장일수도 있다. [5] 과거 C언어의 16비트에서 32비트로의 전환기에 헬게이트가 열렸었다. [6] Java 코드를 Kotlin에서 갖다 쓸 때에는 내부 식별자와 외부 식별자가 일치(내부 필드는 data이고, 외부 접근 메서드는 getData(), setData())해도 문제가 되지 않으나, Kotlin 네이티브인 경우는 식별자 이름 충돌 등 심각한 문제가 된다.