C언어에서 가변 파라메터를 가지는 함수

By | 2009년 6월 10일

순수 C언어 함수는 일반적으로 함수 파라메터의 갯수가 고정적이고 OOP에서 보이는 오버로딩과 같이 하나의 함수이름으로 서로 다른 파라메터를 가지는 함수를 사용할 수 없다. 그런데 C언어 함수 중 printf()류의 함수는 파라메터가 최소 1 개 이상으로 가변적이다. 예를 들면 아래 printf 함수는 동일한 결과를 출력하지만 사용한 파라메터의 갯수는 다르다.


printf(“Hello World!”); /* 파라메터 1개 사용 */
printf(“Hello %s!”, “World”); /* 파라메터 2개 사용 */
printf(“%s %s!”, “Hello”, “World”); /* 파라메터 3개 사용 */


그러면 어떻게 이런 함수를 작성할 수 있을까? 해결책은 헤더파일 “stdarg.h”에 정의돼 있다. 이 파일에 보면 va_list 타입과 네 가지의 매크로 va_start, va_arg, va_end, va_copy 가 정의돼 있는데, 이 매크로들이 가변 파라메터를 처리하는데 사용된다.


va_list
이 타입은 가변 파라메터를 위한 데이터 타입으로 가변 함수 정의 부분에서 가변 파라메터를 처리하기 위해 선언한다.

void va_start(va_list ap, last);
이 매크로는 가변 파라메터(ap)의 시작위치를 함수에 주어진 마지막 고정 파라메터(last) 다음으로 초기화 해 주며, 일반적으로 함수의 첫 부분에 사용된다.

type va_arg(va_list ap, type);
이 매크로는 가변 파라메터(ap) 에서 주어진 타입(type)의 값을 읽고 가변 파라메터(ap)의 위치를 다음으로 이동시킨다.

void va_end(va_list ap);
이 매크로는 함수의 마지막 부분에 사용한다.

void va_copy(va_list dest, va_list src);
이 매크로는 src에 저장된 가변 파라메터를 dest로 복사한다.


그리고 가변 함수를 정의할 때 최소 한 개 이상의 파라메터는 반드시 정상적으로 “int a”와 같이 타입과 변수명을 선언해야 하며 나머지 가변 파라메터 부분은 “…”으로 선언하면 된다. 이 때 “…”은 함수 파라메터의 맨 마지막에 선언해야 한다.


사용법은 아래 프로그램을 참조하자. 아래 작성한 프로그램의 함수 sum은 가변 파라메터를 가지는 함수로, 주어진 파라메터의 값이 -1을 만날 때까지 파라메터에 전달된 정수의 합을 계산한다.


#include <stdio.h>
#include <stdarg.h>

int sum_list(int a, )
{
    va_list ap; /* 가변 파라메터 저장을 위한 변수 ap 선언 */
    int i, sum = 0;

    va_start(ap, a); /* 가변 파라메터가 a 다음부터 시작됨을 알림 */

    i = a;
    while(i != -1) {
        sum += i;
        i = va_arg(ap, int); /* 가변 파라메터에서 정수 값을 읽고 다음 값을 읽기 위해 준비 */
    }

    va_end(ap); /* 가변 파라메터를 다 사용함 */

    return sum;
}

int main(int argc, char *argv[])
{
    printf(“%d\n”, sum_list(-1)); /* 0 출력 */
    printf(“%d\n”, sum_list(1,-1)); /* 1출력 */
    printf(“%d\n”, sum_list(1,2,-1)); /* 3 출력 */
    printf(“%d\n”, sum_list(1,2,3,-1)); /* 6출력 */
    printf(“%d\n”, sum_list(1,2,3,4,-1)); /* 10 출력 */
    printf(“%d\n”, sum_list(1,2,3,4,5,-1)); /* 15 출력 */
    printf(“%d\n”, sum_list(1,2,3,4,5,6,-1)); /* 21 출력 */
    printf(“%d\n”, sum_list(1,2,3,4,5,6,7,-1)); /* 28 출력 */
    printf(“%d\n”, sum_list(1,2,3,4,5,6,7,8,-1)); /* 36 출력 */
    printf(“%d\n”, sum_list(1,2,3,4,5,6,7,8,9,-1)); /* 45 출력 */
    printf(“%d\n”, sum_list(1,2,3,4,5,6,7,8,9,10,-1)); /* 55 출력 */

    return 0;
}


다음은 “FreeBSD Library Functions Manual Man Page”에 제시된 또다른 예제 프로그램이다. 이 예제의 va_arg 매크로를 보면 가변 파라메터의 타입이 서로 다른 것도 처리할 수 있음을 알 수 있다.


void foo(char *fmt, …)
{
    va_list ap;
    int d;
    char c, *s;

    va_start(ap, fmt);
    while (*fmt)
        switch(*fmt++) {
            case ‘s’: /* string */
                          s = va_arg(ap, char *);
                          printf(“string %s\n”, s);
                          break;
            case ‘d’: /* int */
                          d = va_arg(ap, int);
                          printf(“int %d\n”, d);
                          break;
            case ‘c’: /* char */
                          /* Note: char is promoted to int. */
                          c = va_arg(ap, int);
                          printf(“char %c\n”, c);
                          break;
        }
    va_end(ap);
}

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

이 사이트는 스팸을 줄이는 아키스밋을 사용합니다. 댓글이 어떻게 처리되는지 알아보십시오.