인자 개수에 따라 다르게 동작하는 매크로 함수
매크로 함수를 만드는데, 인자 개수에 따라 다른 동작을 하고 싶습니다. 어떻게 하면 좋을까요? 가장 간단한 방법은 인자 개수별로 매크로 함수를 따로 만드는 것입니다.
#define func1(a)
#define func2(a, b)
#define func3(a, b, c)
#define func4(a, b, c, d)
이 방식은 인자 개수가 몇 개인지 세어서 개수에 맞는 함수를 호출해야만 한다는 문제가 있습니다. 이를 해결하려면 C++의 함수 오버로딩처럼 일종의 제네릭한 매크로 함수를 만들어야 합니다. 다음과 같이 정의하면 가능합니다.
#define VA_GENERIC(_1, _2, _3, _4, x, ...) x
#define func(...) VA_GENERIC(__VA_ARGS__, func4, func3, func2, func1)(__VA_ARGS__)
예를 들어 func(1, 2, 3)
은 아래와 같이 확장됩니다.
func(1, 2, 3)
VA_GENERIC(1, 2, 3, func4, func3, func2, func1)(1, 2, 3)
func3(1, 2, 3)
이 예제는 인자 개수를 최대 4개까지만 지원하는데 VA_GENERIC
의 정의를 수정하여 얼마든지 늘릴 수 있습니다.
응용
가변 인자 함수의 인자 개수 자동으로 계산하기
가변 인자 함수는 인자 개수를 자동으로 구해주지 않습니다. 첫 번째 인자로 인자 개수를 직접 계산해서 넣어주거나 최소한 첫 번째 인자로부터 총 인자 개수를 구할 수 있어야 합니다. 표준 라이브러리의 printf
는 첫 번째 인자로 포맷 문자열을 받아 이를 보고 인자 개수를 계산합니다. 보통은 다음과 같이 인자 개수를 직접 넣어주죠.
int add_int(int argc, ...) {
va_list ap;
int sum = 0;
va_start(ap, argc);
for (int i = 0; i < argc; i++) {
int n = va_arg(ap, int);
sum += n;
}
va_end(ap);
}
위의 VA_GENERIC
매크로를 사용하면 첫 번째 인자 argc
를 자동으로 구할 수 있습니다.
#define NUM_VA_ARGS(...) VA_GENERIC(__VA_ARGS__, 4, 3, 2, 1)
#define ADD_INT(...) add_int(NUM_VA_ARGS(__VA_ARGS__), __VA_ARGS__)