상수가 소리 지르게 하지 말자

C/C++를 비롯해 많은 프로그래밍 언어에서 상수를 흔히 대문자로 표기한다. 오랫동안 사용한 관례라는 이유로 대문자 표기를 선호하기도 하고, 프로그래밍 관련 책에서도 여전히 많이 볼 수 있는 표기법이긴 하지만 여전히 대문자로 표기해야 할까는 의문이다. C++에서 상수는 매크로와 다른데 이를 구별할 수 없으며, 굳이 상수라고 변수와 달리 표기해야 할까 싶다. 리터럴이 아닌 이상 단지 값을 변경하지 못하는 변수에 불과하며, 실수로 대입하더라도 컴파일러에서 알려주니 전혀 문제될 것이 없음에도 말이다. 많이 알려진 구글 C++ 가이드에서도 상수는 변수와 동일한 명명 규칙을 사용하지만, 단순히 그런 이유보다는 이 의문에 좀 더 확신을 얻고 싶어 찾아 봤더니 공감가는 글이 있어 편역해 본다.

 

원문: Stop the Constant Shouting by Jonathan Wakely @ACCU

C/C++에서는 일반적으로 다음 예처럼 상수를 대문자로 표기한다.

하지만 C++에서 이는 끔찍한 관례일 뿐이다.

상수에 대문자 이름을 사용한 건 (적어도) C 초기 시절, 매크로나 열거자로 정의한 기호 상수를 변수와 구별해야 했던 때로 거슬러 올라간다.

Symbolic constant names are conventionally written in upper case so they can be readily distinguished from lower case variable names.

다음은 이를 따르는 매크로 정의이다.

이러한 관례가 C에서는 일리가 있다. 오랫동안 C에는 const 키워드가 없었으며 심지어 오늘날에도 (고정 길이) 배열 경계나 비트 필드 크기를 선언하는 등 상수 표현식을 써야 할 때 const 변수를 사용할 수 없다. 게다가 변수와 달리 기호 상수에는 주소가 없으며 새 값을 대입할 수 없다. 그러므로 유감스럽게도 매크로는 C에서 상수를 정의하기 위한 필요악이며, 변수와 구별하는 것이 유용할 뿐만 아니라 일관된 명명 관습이 이에 도움이 될 수 있다는 점을 인정할 수 밖에 없다. (모든 이름을 대문자로 표기하는 것처럼) 특정 목적으로 예약해 둔 식별자 집합은 일종의 이름 공간(namespace)을 형성해, 한눈에 STEPstep이 서로 다른 이름이며 전통적인 C 관례에 따라 하나는 기호 상수이고 다른 것은 변수임을 추정할 수 있다.

그러나 기호 상수처럼 평범한 무언가에 코드에서 눈에 잘 띄고(VISIBLE) 주목을 끄는(ATTENTION) 이름을 전통적인 관례로 예약해 둔다는 점은 매우 유감이다. 예를 들면 C_처럼 공용 접두어를 쓰는 등 다른 방법도 있었겠지만 거의 반세기가 지난 지금 C 관례를 바꾸기엔 너무 늦었다.

상수를 정의할 때 C++에서는 C의 제약과 달리 상수 표현식으로 초기화한 const 변수는 상수 표현식 그 자체이며 constexpr 함수는 컴파일 시점에 상수를 만들어 낼 수 있다. 게다가 언어에서 이름 공간을 지원하므로 아래처럼 정의해 STEP 대신 FahrenheitToCelsiusConstants::step으로 참조할 수 있다.

이는 적절한 타입과 유효 범위로 상수를 정의하는 데 매크로보다 훨씬 더 나은 도구가 있음을 뜻한다.

Macros are very important in C but have far fewer uses in C++. The first rule about macros is: Don’t use them unless you have to.

이와는 별개로 매크로를 피해야 할 이유가 있다. <windows.h>에서 정의한 minmax 매크로 문제가 그렇다. 주된 문제점은 매크로가 어휘적 유효 범위(lexical scope)를 지키지 않으며 전처리기에서는 함수, 변수, 이름 공간, 여러분이 직접 명명한 것 등 이름이 같으나 매크로가 아닌 모든 것을 짓밟고 행복하게 재정의한다는 점이다.

Preprocessing is probably the most dangerous phase of C++ translation. The preprocessor is concerned with tokens (the “words” of which the C++ source is composed) and is ignorant of the subtleties of the rest of the C++ language, both syntactic and semantic. In effect the preprocessor doesn’t know its own strength and, like many powerful ignoramuses, is capable of much damage.

따라서 C++에서 매크로는 (이상적인 코드에서는) 그다지 필요하지 않을 뿐더러 별로 쓰지도 않지만, 써야 한다면 문제를 최소화하고 코드를 읽는 개발자의 주목을 끌지 않도록 하는 게 중요하다. C++ 이름 공간으로 매크로 유효 범위를 제한할 수는 없지만, 매크로가 아닌 것과 충돌해 소리소문 없이 재정의하는 문제를 피하기 위해 이름 집합을 예약하는 형식으로 임시 이름 공간을 사용할 수 있다. 관례적으로는 (한 글자 이름 또는 매크로에 도움이 되지 않는 설명적이지 못한 짧은 이름을 제외한) 대문자 이름을 사용한다.

Also to warn readers, follow the convention to name macros using lots of capital letters.

By convention, macro names are written in uppercase. Programs are easier to read when it is possible to tell at a glance which names are macros.

대문자 이름을 사용하면 일반적인 C++의 구문과 의미 규칙을 따르지 않는 이름에 주목하도록 소리 지르는 부가 효과가 있다.

Do #undefine macros as soon as possible, always give them SCREAMING_UPPERCASE_AND_UGLY names, and avoid putting them in headers.

매크로 이름을 다른 코드와 명확히 구분하면 그 이름을 재사용하지 않도록 주의하거나, 예를 들면 중복 평가 같은 부작용을 알고 주의해서 사용해야 한다는 것을 알 수 있다.

하지만 매크로가 아님에도 모두 대문자로 표기한다면 이름 공간을 오염시키게 된다. 여러분의 코드를 짓밟는 강력한 무식쟁이(ignoramus)를 소환하려는 이름이 무엇인지 알 수 있는 이점을 더 이상 누리지 못할 것이고, 다른 코드와 현저히 다르게 눈에 띄는 이름이 배열 경계처럼 해롭지 않고 평범한 무언가일 수도 있다. 일반적으로 상수보다는 이를 사용하는 코드가 더 흥미로우며 개발자의 주목을 받아야 한다. 매크로와 상수의 정의는 같으나 그 이름의 대소문자만 바꿔 앞에서 본 코드 조각과 비교해 보자.

n이 증가한다는 것보다 반환 값을 어떤 상수 LIMIT로 제한한다는 것에 주목하는 것이 더 중요할까? 아니면 max나 다른 함수가 아닌 min을 호출한다는 것에 비해서는 어떨까? 여기서 LIMIT에 주목해야 하는 이유를 모르겠다. 심지어 그 제한이 무엇인지 알 수 없을 뿐만 아니라, n이 두 번 증가할 거라는 점도 명확히 드러나지 않는다.

이제 C++ 프로그래머에게 호소하고 싶다. 매크로가 아닌 상수를 대문자로 쓰지 말자. 여러분의 코드를 읽는 개발자에게 경고하고 강력한 무식쟁이가 일으킬 수 있는 피해를 제한하기 위해 매크로만 모두 대문자로 쓰자.

 

Notes:
1. 물론 외국 C++ 관련 서적에서는 상수를 굳이 대문자로 표기하지 않고 변수와 같은 명명 규칙으로 표기하는 사례도 많다.
2. The C Programming Language, Second Edition, Brian W. Kernighan & Dennis M. Ritchie, Prentice Hall, 1988.
3. The C++ Programming Language, Special Edition, Bjarne Stroustrup, Addison-Wesley, 2000.
4. C++ Gotchas, Stephen C. Dewhurst, Addison Wesley, 2002.
5. T같은 한 글자 이름은 흔히 템플릿 매개변수에 사용한다
6. The C++ Programming Language, Special Edition, Bjarne Stroustrup, Addison-Wesley, 2000.
7. ‘The GNU Compiler Collection: The C Preprocessor’, Free Software Foundation, 2014, http://gcc.gnu.org/onlinedocs/cpp/Object-like-Macros.html#Object-like-Macros
8. C++ Coding Standards, Herb Sutter & Alexei Alexandrescu, Addison-Wesley, 2005.
물론 외국 C++ 관련 서적에서는 상수를 굳이 대문자로 표기하지 않고 변수와 같은 명명 규칙으로 표기하는 사례도 많다.
The C Programming Language, Second Edition, Brian W. Kernighan & Dennis M. Ritchie, Prentice Hall, 1988.
The C++ Programming Language, Special Edition, Bjarne Stroustrup, Addison-Wesley, 2000.
C++ Gotchas, Stephen C. Dewhurst, Addison Wesley, 2002.
T같은 한 글자 이름은 흔히 템플릿 매개변수에 사용한다
The C++ Programming Language, Special Edition, Bjarne Stroustrup, Addison-Wesley, 2000.
‘The GNU Compiler Collection: The C Preprocessor’, Free Software Foundation, 2014, http://gcc.gnu.org/onlinedocs/cpp/Object-like-Macros.html#Object-like-Macros
C++ Coding Standards, Herb Sutter & Alexei Alexandrescu, Addison-Wesley, 2005.

You may also like...