1 minute read

nil

Project Property > Configuration Properties > C/C++ > Preprocessor > Preprocessor Definitions에 DONT_USE_DIRECT_$(USERNAME) 를 정의한다.

// feature.h
#ifdef DONT_USE_DIRECT_ohyecloudy
# define PROGRAMMER_ohyecloudy 1
#else
# define PROGRAMMER_ohyecloudy 0
#endif

// ...

#define WORKING_WHILE_FEATURE_TETSUZANKOU PROGRAMMER_ohyecloudy | PROGRAMMER_ohyesunny
#define WORKING_WHILE_FEATURE_...

한 곳에서 매크로를 만든다.

// tetsuzankou.cpp
#include "feature.h"
#if !defined(WORKING_WHILE_FEATURE_TETSUZANKOU)
#      error "WORKING_WHILE_FEATURE_TETSUZANKOU is not defined!"
#endif

// ...

#if WORKING_WHILE_FEATURE_TETSUZANKOU
ISkill * skill = new Tetsuzankou();
#else
ISkill * skill = new NullSkill();
#endif

// ...

이런 식으로 사용한다.

왜?

잦은 커밋을 선호한다. 분산 버전 관리 시스템(distributed version control system)을 사용 안 하고 있다. 피처(feature)마다 브랜치(branch)를 사용하지 않는다. 이러다 보니 개발용 매크로를 사용하게 되더라. 매크로가 나쁘다지만 모두를 공포에 떨게 할 대규모 커밋을 피하는 게 더 중요하다. 그리고 끝까지 갈 것도 아니고 중간 단계에서만 사용하고 다 없어질 운명이다.

게임 콘솔 명령어나 개발용 설정 파일로 제어가 가능한 것은 매크로를 사용하지 않는다. 이걸로 안 되는 거. 되긴 되는데 하루 안에 제어가 가능한 상태로 못 만드는 것. 뭐 이러면 매크로를 사용한다.

//#define TEST_FEATURE_A

#ifdef TEST_FEATURE_A
#endif

커밋할 때는 주석 처리하고 최신으로 받아서 내 자리에서 테스트할 때는 주석 풀고. 커밋할 때 다시 주석 처리하고. 이거 딱 실수하기 좋다. 나도 이런 실수를 몇 번 했었다. 이런 실수는 봉쇄된다.

#if, #ifdef

token-string을 1 또는 0으로 정의하는 걸 규칙으로 만들었다. 이렇게 하면 식별자(identifier)를 정의한 header 파일을 include 안 한 결함이 바로 발견되기 때문이다.

만약 token string 없이 식별자만 정의한다면? 매크로를 정의한 파일을 include 했는지 검사할 방법이 없다. include를 빼놓는다면 코드가 preprocessor 난도질에서 살아남지 못하겠지. 프로젝트 설정에서는 token string 없이 식별자만 정의하고 코드에서는 1 또는 0으로 정의하는 걸 선호한다.

DONT_USE_DIRECT_ohyecloudy?

바로 사용하는 걸 막으려고. 식별자를 한곳에 모아놔야지 찾기가 쉽다. 만약 이렇게 USERNAME을 사용해 만든 식별자를 코드에 바로 쓴다면? 의도 파악이 힘들다. 그리고 찾기도 힘들어. 왜냐면 프로그래머 아이디를 쓰기 때문에.

그래서 feature.h에 다 모으고 다시 1 또는 0으로 정의한다. 0/1로 정의하는 이유는 || 연산자를 사용할 수 있기 때문이다. 이걸 사용하면 게임 콘솔 명령어로 빼기 전 프로그래머 여러 명이 작업해야 할 때, 편리하다.

사용한다면 한군데 모아놓고 편하게 관리하자. 실수도 방지하고.

PS: Tetsuzankou는 철산고. 버추어 파이터에서 아키라가 사용하는 기술. 격투 게임에서 가장 좋아하는 기술이다.