개요
C 언어는 줄임표(...) 문법을 통해 함수가 미리 정해지지 않은 개수의 인자를 전달받을 수 있도록 지원합니다. 이를 가변 인자(variable arguments)라고 합니다. 다만 가변 인자에는 그 개수에 대한 정보가 자동으로 포함되지 않기 때문에, 프로그래머가 직접 개수를 파악할 수 있는 장치를 마련해야 합니다.
일반적으로 다음 세 가지 방법 중 하나를 사용합니다.
- 첫 번째 인자로 개수 전달: 함수 호출 시 인자의 총 개수를 첫 번째 매개변수로 넘깁니다.
- 마지막 인자로 NULL 전달: 인자 목록의 끝을 표시하는 센티널(sentinel) 값을 넣어 더 이상 인자가 없음을 알립니다. (예:
execl()계열 함수) - 포맷 문자열 활용:
printf()나scanf()처럼 첫 번째 인자에 포함된 플레이스홀더(%d, %s 등)의 개수로 나머지 인자의 수를 유추합니다.
다음 예제에서는 첫 번째 방법을 적용해, 여러 개의 정수 인자와 그 개수를 함께 전달하고 평균을 구하는 프로그램을 살펴보겠습니다.
예제 코드
#include <stdio.h>
#include <stdarg.h>
double get_avg(int count, ...) {
va_list ap; // 가변 인자 목록을 가리키는 변수
int i;
int sum = 0;
va_start(ap, count); // 마지막 고정 인자(count) 이후부터 인자 접근 시작
for (i = 0; i < count; i++) {
sum += va_arg(ap, int); // int 타입으로 인자를 하나씩 읽어 합산
}
va_end(ap); // 인자 접근 종료 후 반드시 호출
return (double)sum / count; // 평균 반환
}
int main() {
printf("전달된 인자 5개의 평균: %f\n", get_avg(5, 8, 5, 3, 4, 6));
return 0;
}
코드 설명
가변 인자를 처리하려면 <stdarg.h> 헤더에 정의된 매크로들을 사용해야 합니다.
va_list: 가변 인자 목록을 순회하기 위한 타입입니다.va_start(va_list, last_fixed_arg): 마지막 고정 인자 이후의 가변 인자 접근을 시작합니다.va_arg(va_list, type): 현재 위치의 인자를 지정한 타입으로 읽고 다음 인자로 이동합니다.va_end(va_list): 가변 인자 접근을 마무리합니다.
위 예제에서는 첫 번째 인자 count에 실제 데이터 인자의 개수(5)를 전달했기 때문에, 루프를 정확히 5번만 반복하며 값을 읽을 수 있습니다.
실행 결과
전달된 인자 5개의 평균: 5.200000
(8 + 5 + 3 + 4 + 6) ÷ 5 = 5.2가 올바르게 계산되어 출력됩니다.
정리
가변 인자 함수는 편리하지만, 컴파일러가 인자의 개수와 타입을 검사해 주지 않는다는 점에 유의해야 합니다. 따라서 개수를 함께 전달하거나 센티널 값을 두는 등의 규칙을 명확히 정하는 것이 안전하며, va_arg로 값을 읽을 때 실제 전달된 타입과 다른 타입을 지정하면 정의되지 않은 동작(undefined behavior)이 발생할 수 있으므로 주의해야 합니다.