가변 인자
가변 인자 (Variadic arguments)
함수에 넘길 인자의 개수를 상황에 따라 바꾸고 싶다면 **가변 인자 함수(variadic function)**를 쓰면 돼요. printf처럼 호출할 때마다 인자의 개수가 달라지는 함수가 대표적이에요.
출처: cppreference
본문
가변 인자 함수는 서로 다른 개수의 인자로 호출될 수 있는 함수예요. 프로토타입이 있는 함수 선언만 가변 인자일 수 있어요. 이는 매개변수 목록의 맨 마침에 와야 하는 ... 형태의 매개변수로 나타내요 (C23 이전에는 뒤에 적어도 하나의 이름 붙은 매개변수가 반드시 있어야 했어요). 생략 기호 매개변수와 그 앞 매개변수는 ,로 구분돼야 해요.
// Prototyped declaration
int printx(const char* fmt, ...); // function declared this way
printx("hello world"); // may be called with one
printx("a=%d b=%d", a, b); // or more arguments
int printz(...); // OK since C23 and in C++
// Error until C23: ... must follow at least one named parameter
// int printy(..., const char* fmt); // Error: ... must be the last
// int printa(const char* fmt...); // Error in C: ',' is required; OK in C++
함수 호출 시, 가변 인자 목록의 일부인 각 인자는 **기본 인자 승격(default argument promotions)**이라는 특별한 묵시적 변환을 거쳐요.
가변 인자를 쓰는 함수 본문에서는 <stdarg.h> 라이브러리 시설로 이 인자들의 값을 접근할 수 있어요.
| 헤더 | 시설 |
|---|---|
<stdarg.h> |
va_start · va_arg · va_copy · va_end · va_list |
참고
옛 스타일(프로토타입 없는) 함수 선언은 뒤따르는 함수 호출이 어떤 개수의 인자든 쓰는 걸 허용하지만, (C89 기준으로) 가변 인자일 수는 없어요. 그런 함수의 정의는 고정된 개수의 매개변수를 지정해야 하고 stdarg.h 매크로는 쓸 수 없어요.
// old-style declaration, removed in C23
int printx(); // function declared this way
printx("hello world"); // may be called with one
printx("a=%d b=%d", a, b); // or more arguments
// the behavior of at least one of these calls is undefined, depending on
// the number of parameters the function is defined to take
예제
여기서는 시간 스탬프를 붙여 로그를 찍는 tlog 함수를 만들어, 가변 인자와 vprintf가 어떻게 함께 쓰이는지 확인해 볼게요.
#include <stdio.h>
#include <time.h>
#include <stdarg.h>
void tlog(const char* fmt,...)
{
char msg[50];
strftime(msg, sizeof msg, "%T", localtime(&(time_t){time(NULL)}));
printf("[%s] ", msg);
va_list args;
va_start(args, fmt);
vprintf(fmt, args);
va_end(args);
}
int main(void)
{
tlog("logging %d %d %d...\n", 1, 2, 3);
}
출력:
[10:21:38] logging 1 2 3...
더 알아보기
- 가변 인자를 실제로 꺼내 쓰는 방법은
<stdarg.h>문서에서va_list,va_start,va_arg를 차례로 보면 돼요. - 가변 인자가 기본 인자 승격을 거치는 이유는 묵시적 변환 문서에서 설명해요.
- C++의 가변 인자(variadic arguments)도 같은 아이디어를 다루니 비교해 보세요.