Up

인자 개수에 따라 다르게 동작하는 매크로 함수

인자 개수에 따라 다르게 동작하는 매크로 함수

매크로 함수를 만드는데, 인자 개수에 따라 다른 동작을 하고 싶습니다. 어떻게 하면 좋을까요? 가장 간단한 방법은 인자 개수별로 매크로 함수를 따로 만드는 것입니다.

#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)은 아래와 같이 확장됩니다.

  1. func(1, 2, 3)
  2. VA_GENERIC(1, 2, 3, func4, func3, func2, func1)(1, 2, 3)
  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__)