최근 수정 시각 : 2023-11-20 01:41:37

헝가리안 표기법

파일:관련 문서 아이콘.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라는게 다들 부실했기 때문에 물론 볼랜드의 Turbo C 같은 예외도 있었지만 이 규칙이 엄청난 센세이션을 불러 일으켰다. 하지만 지금은 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. 장점

  • 데이터 타입을 변수명에서 바로 추정할 수 있다.
  • IDE가 없을 때 작업하는 경우 (특히 vi나 emacs로 터미널에서 작업할 때) 여러모로 유리해진다.
  • 같은 의미를 가지는 서로 다른 타입의 변수가 있을 때 이름 충돌을 방지할 수 있다.

4. 단점

  • 아이러니하게도, 코드를 단번에 파악하기 힘들어진다.
  • 변수나 함수 인자의 이름을 기억하기가 힘들다.
  • 데이터 타입이 바뀌면 변수 또는 함수 인자의 이름을 바꿔야 한다. 리팩토링을 지원하는 IDE가 없으면 지옥도가 펼쳐질 것이다. 특히 PHP JavaScript, Python, Ruby 같은 동적 타입 언어와의 궁합은 최악.
  • C/ C++일 경우 언어 명세에서 데이터 타입의 크기를 강제하지 않은 바람에 시스템 아키텍처에 따라 데이터 타입의 크기가 다르다는 무시 못할 문제가 있다.[5] 예를 들어 w는 16비트일까? 32비트일까? 64비트일까?
  • 같은 의미를 가지는 서로 다른 타입의 변수가 있을 때 이것들을 왜 선언했는지를 잊어버렸을 경우, 코드를 이해하기가 어려워진다.

5. 몰락

디스플레이 화면이 커지면서 한 눈에 볼 수 있는 코드의 양이 많아지고, IDE가 눈부시게 발전한 덕분에 헝가리안 표기법은 단숨에 구식으로 변하고 말았다. 마우스 커서만 올리면 해당 심볼의 데이터 타입이 뙇!하고 나오고, 심볼이 어느 위치에서 선언되었는지 단축키 한 번으로 이동할 수 있으며, 심볼이 코드의 어느 위치에서 어떻게 참조되고 있는지 한 눈에 확인할 수 있는 마당에, 고작 타입을 명시한답시고 심볼의 이름을 불필요하게 늘이는 것은 비생산적이기 짝이 없는 행위일 뿐이다.

애초에 헝가리안 표기법 자체가 정적 타입 언어가 대세인 시절에 나온 것이다 보니 Python이나 JavaScript처럼 한참 후에 등장한 동적 타입 언어에는 적용해봐야 큰 의미가 없다. Python 3.X 버전 중반부터 추가된 타입 개념이나 JavaScript에 타입 개념을 도입한 TypeScript 등에서도 알수 있듯 기존의 동적 타입 언어들도 정적 타입 언어의 장점을 취해 프로그래밍할 수 있도록 하는 것이 현대 프로그래밍 언어 발전의 흐름이지만, 결국 이런 움직임이 발생하는 가장 큰 이유 중 하나가 고성능 IDE를 더 효율적으로 활용[6]하도록 하기 위함이라는 것을 생각해 보면 더더욱 헝가리안 표기법을 쓸 이유가 없다.

최근에는 클래스의 멤버 변수나 메소드에 _를 붙이는 정도로 간소화 해서 쓰인다. 특히 개발 언어가 public/protected/private 등의 접근 제한자를 지원하지 않거나 부분적으로만 지원한다면, 클래스 멤버의 접근 수준을 명시하기 위해 이러한 표기법이 매우 강력하게 권장된다. 가령 Python은 언어 차원에서의 접근 제한자를 지원하지 않지만, 개발자들은 멤버 이름 앞의 _protected로, __private으로 간주한다.

또한 데이터의 논리적인 상태를 나타내는 Apps Notation은 지금도 간간히 쓰이고 있다.

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] 과거 16비트에서 32비트로의 전환기에도 헬게이트가 열렸었으며, 2010년대는 소프트웨어가 AMD x86-64로 이관하는 과정이 진행 중이기 충분히 생길 수 였는 문제였다. [6] 잘못된 심볼 사용에 대한 에러 알림, 코드 자동 완성, 리팩토링 등은 컴파일 타임에 IDE가 타입을 해석할 수 있어야 원활하게 동작하는 경우가 많다.