Skip to content

Cstdarg

C의 가변인자.

Implementation

va_list
각 가변 인자의 시작 주소를 가리킬 포인터입니다. 모양은 멋있게 생겼지만 내부적으로는 char *로 정의되어 있는 녀석입니다.
va_start
va_list로 만들어진 포인터에게 가변인자 중 첫 번째 인자의 주소를 가르쳐주는 중요한 매크로입니다. 이 녀석의 모양은 사실 이렇게 생겼습니다. (Microsoft Visual Studio 기준)

:

#define va_start(ap, v)  ( (ap) = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )

:* ap: va_list 로 만든 포인터가 담깁니다.

:* v: 마지막 고정인수가 담깁니다.

:* _ADDRESSOF(v) => &(v), 즉 주소로 바꿔주는 매크로입니다.

:* _INTSIZEOF(n) => ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) ), 마지막 고정인수의 사이즈를 구해서 그 다음 인자의 시작주소. 즉, 가변인자의 시작주소까지의 메모리상의 거리 를 구해주는 매크로입니다.

va_arg
특정 가변인자를 가리키고 있는 va_list의 포인터를 다음 가변인자로 이동시켜 주는 매크로입니다. 이 녀석의 모양은 아래와 같습니다.

:

#define va_arg(ap,t)    ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )

:* ap: va_list로 만든 포인터가 담깁니다.

:* t: intlong, double과 같은 타입 이름이 담깁니다.

참고로 char, short 의 경우에는 int로 대신 쓰고, flaot의 경우에는 double로 대신 쓴 이후 형 변환을 해주어야 한다고 합니다. (예. char ch = (char) va_arg(ap, int); )
va_end
사용한 가변인자 변수를 끝낼때 사용합니다. 단순히 모양을 보면 NULL 포인터로 돌려주는 매크로인데, 프로그램상 어떤 경우가 생길 지 모르니까 놓치지 말고 써주도록 합시다.

:

#define va_end(ap)      ( ap = (va_list)0 )

:* ap: va_list로 만든 포인터가 담깁니다.

Example

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

int sum(int, ...);

int main(void) {
   printf("Sum of 10, 20 and 30 = %d\n",  sum(3, 10, 20, 30) );
   printf("Sum of 4, 20, 25 and 30 = %d\n",  sum(4, 4, 20, 25, 30) );

   return 0;
}

int sum(int num_args, ...) {
   int val = 0;
   va_list ap;
   int i;

   va_start(ap, num_args);
   for(i = 0; i < num_args; i++) {
      val += va_arg(ap, int);
   }
   va_end(ap);

   return val;
}

Printf example

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

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 */
            /* need a cast here since va_arg only
               takes fully promoted types */
            c = (char) va_arg(ap, int);
            printf("char %c\n", c);
            break;
        }
    va_end(ap);
}

va_list 전달 방법

void _printf(const char * format, ...)
{
    char buffer[2048] = {0,};
    va_list args;
    va_start(args, format);
    vsnprintf(buffer, 2048, format, args);
    va_end(args);

    _print(buffer);
}

See also

Favorite site

References


  1. Norux.me_-_How_to_use_the_va_list.pdf