variable argument list, va_list, 가변형 인자 본문

Programming/C

variable argument list, va_list, 가변형 인자

halatha 2008. 7. 2. 14:40

gcc 3.4.5 (mingw), Windows XP


가변 길이의 매개변수 리스트(Variable-length Argument Lists)

 

이 절에서는 printf의 최소 버전(Version) minprintf를 소개한다. 이 함수는 가변 길이 매개 변수를 포터블(portable : 다른 컴퓨터 상에도 쉽게 이식 가능한)하게 처리할 수 있는 함수이다.

우리들은 주로 매개변수의 처리만에 관심을 가지고 있으므로, minprintf 함수는 출력형식 지정 문자열과 매개변수를 처리하기 위해서 printf를 호출하여 사용할 것이다. printf에 대한 선언은 다음과 같이 한다.

int printf(char *fmt, )

여기서 의 의미는 매개변수의 형과 개수가 변할 수 있음을 뜻한다. 은 매개변수 리스트의 끝에만 나타날 수 있다. minprintf는 다음과 같이 정의한다.

void minprintf(char *fmt, )

표준헤더 <stdarg.h>는 매개변수 리스트를 어떤 식으로 처리하느냐가 정의된 매크로를 포함하고 있다. 이 헤더는 기종마다 다르게 만들어지지만 헤더를 사용하는 방법은 기종에 상관없이 동일하다.

va_list (type)은 매개변수를 차례로 가리키는 포인터 변수를 정의할 때 사용된다. minprintf에서 이 변수는 매개변수 포인터(argument pointer)의 첫 글자만을 따와서 ap라 명명했다. 매크로 va_list는 첫번째 이름없는 매개변수를 지시하게 끔 ap의 초기값을 설정한다. ap가 사용되기 전에 va_start를 한번 호출해야 한다. 매개변수 중에는 이름을 가진 것이 적어도 하나 있어야 한다. 이름 붙여진 매개 변수중 마지막 것은 va_start를 시작하기 위해 사용되어진다.

va_arg를 호출하면 하나의 매개변수를 리턴하고 ap가 다음 매개변수를 가리키게 한다. va_arg는 어떤 형이 리턴될 것이며, ap가 얼마나 전진해야 될지를 결정하기 위해 형 이름을 참고한다. 마지막으로, va_end는 청소 작업을 한다. 이것은 함수가 리턴되기 전에 호출되어야 한다.

이런 동작을 하는 minprintf 함수는 다음과 같다.

//    cf : vprintf, vfprintf, vsprintf, vsnprintf
#include <stdarg.h>

//    minprintf : minimal printf with variable argument list
void minprintf(char* fmt, ...)
{
    va_list    ap;    //    points to each unnamed arg in turn
    char    *p, *sval;
    int    ival;
    double    dval;

    va_start(ap, fmt);    //    make ap point to 1st unnamed arg
    for ( p = fmt; *p; p++ )
    {
        if ( *p != '%' )
        {
            putchar(*p);
            continue;
        }
        switch ( *++p )
        {
        case 'd':
            ival = va_arg(ap, int);
            printf("%d", ival);
            break;
        case 'f':
            dval = va_arg(ap, double);
            printf("%f", dval);
            break;
        case 's':
            for ( sval = va_arg(ap, char*); *sval; sval++ )
                putchar(*sval);
            break;
        default:
            putchar(*p);
            break;
        }
    }
    va_end(ap);    //    clean up when done
}

Comments