가변 인자

mtak·2021년 1월 26일
0

42Seoul

목록 보기
7/13

Variable Argument (가변 인자)

printf 같이 매개변수의 개수가 정해지지 않고, 매번 함수에 들어가는 인수의 개수가 변하는 것을 가변인자라고 한다.

1. 가변 인자 함수 만들어보자

함수에서 가변 인자를 정의할 때는 고정 매개변수가 한 개 이상 있어야 하며
고정 매개변수 뒤에 ...을 붙여 매개변수의 개수가 정해지지 않았다는 표시를 해준다.

반환값자료형 함수이름(자료형 고정매개변수, ...)
{
}
#include <stdio.h>
#include <stdarg.h>    // va_list, va_start, va_arg, va_end가 정의된 헤더 파일

void printNumbers(int args, ...)    // 가변 인자의 개수를 받음, ...로 가변 인자 설정
{
    va_list ap;    // 가변 인자 목록 포인터

    va_start(ap, args);    // 가변 인자 목록 포인터 설정
    for (int i = 0; i < args; i++)    // 가변 인자 개수만큼 반복
    {
        int num = va_arg(ap, int);    // int 크기만큼 가변 인자 목록 포인터에서 값을 가져옴
                                      // ap를 int 크기만큼 순방향으로 이동
        printf("%d ", num);           // 가변 인자 값 출력
    }
    va_end(ap);    // 가변 인자 목록 포인터를 NULL로 초기화

    printf("\n");    // 줄바꿈
}

int main()
{
    printNumbers(1, 10);                // 인수 개수 1개
    printNumbers(2, 10, 20);            // 인수 개수 2개
    printNumbers(3, 10, 20, 30);        // 인수 개수 3개
    printNumbers(4, 10, 20, 30, 40);    // 인수 개수 4개

    return 0;
}
10
10 20
10 20 30
10 20 30 40
  • va_list: 가변 인자 목록. 가변 인자의 메모리 주소를 저장하는 포인터.

  • va_start:
    void va_start(va_list ap, variable_name);

    가변 인자를 가져올 수 있도록 포인터를 설정.
    va_list로 만들어진 포인터에게 가변인자 중 첫 번째 선택적 인수(variable_name)의 주소를 가르쳐주는 매크로 함수.

    va_arg(), va_copy(), va_end()에 대한 후속 호출에 대해 ap 포인터를 초기화한다.

    • ap: va_list 로 만든 포인터가 담긴다.
    • variable_name: 인수 목록의 첫 번째 인자 바로 앞에 오는 필수 매개 변수의 이름. 즉, 마지막 고정된 필수 인수가 담긴다.

img

  • va_arg:

    var_type va_arg(va_list ap, var_type);

    가변 인자 포인터에서 특정 자료형 크기만큼 값을 가져옵니다.

    ap로 지정된 위치에서 지정된 var_type 값을 검색하고 리스트에서 다음 인수를 가리키도록 ap 를 증가 시켜 다음 인수가 시작 되는 위치를 결정한다. 즉, 특정 가변인자를 가리키고 있는 va_list의 포인터를 다음 가변인자로 이동시켜 주는 매크로이다.

    • ap: va_list로 만든 포인터가 담긴다.
    • var_type: intlong, double과 같은 타입 이름이 담긴다.
    • 현재 인수를 리턴

    var_type을 설정할 때 char, short 의 경우에는 int로 대신 쓰고, flaot의 경우에는 double로 대신 쓴 이후 형 변환을 해주어야 한다.
    ex) char ch = (char) va_arg(ap, int);

int num = va_arg(ap, int);를 실행하면 현재 ap에서 4바이트(int 크기)만큼 역참조하여 값을 가져온 뒤 ap를 4바이트만큼 순방향으로 이동시킵니다.

img

  • va_end:

     void va_end(va_list arg_ptr);

    모든 인수가 검색 된 후 va_end 는 포인터를 NULL로 다시 설정 한다. 즉, 사용한 가변인자 변수를 끝낼때 사용.

가변 인자 처리가 끝났을 때 포인터(ap)를 NULL로 초기화합니다.

2. 자료형이 다른 가변 인자 함수 만들기

#include <stdio.h>
#include <stdarg.h>    // va_list, va_start, va_arg, va_end가 정의된 헤더 파일

void printValues(char *types, ...)    // 가변 인자의 자료형을 받음, ...로 가변 인자 설정
{
    va_list ap;    // 가변 인자 목록
    int i = 0;

    va_start(ap, types);        // types 문자열에서 문자 개수를 구해서 가변 인자 포인터 설정
    while (types[i] != '\0')    // 가변 인자 자료형이 없을 때까지 반복
    {
        switch (types[i])       // 가변 인자 자료형으로 분기
        {
        case 'i':                                // int형일 때
            printf("%d ", va_arg(ap, int));      // int 크기만큼 값을 가져옴
                                                 // ap를 int 크기만큼 순방향으로 이동
            break;
        case 'd':                                // double형일 때
            printf("%f ", va_arg(ap, double));   // double 크기만큼 값을 가져옴
                                                 // ap를 double 크기만큼 순방향으로 이동
            break;
        case 'c':                                // char형 문자일 때
            printf("%c ", va_arg(ap, char));     // char 크기만큼 값을 가져옴
                                                 // ap를 char 크기만큼 순방향으로 이동
            break;
        case 's':                                // char *형 문자열일 때
            printf("%s ", va_arg(ap, char *));   // char * 크기만큼 값을 가져옴
                                                 // ap를 char * 크기만큼 순방향으로 이동
            break;
        default:
            break;
        }
        i++;
    }
    va_end(ap);    // 가변 인자 포인터를 NULL로 초기화

    printf("\n");    // 줄바꿈
}

int main()
{
    printValues("i", 10);                                       // 정수
    printValues("ci", 'a', 10);                                 // 문자, 정수
    printValues("dci", 1.234567, 'a', 10);                      // 실수, 문자, 정수
    printValues("sicd", "Hello, world!", 10, 'a', 1.234567);    // 문자열, 정수, 문자, 실수

    return 0;
}

img

:warning: GCC에서는 char형 문자일 때 va_arg 매크로에 char 대신 int를 사용해야한다.

case 'c':  // char형 문자일 때
        printf("%c ", va_arg(ap, int));    // int 크기만큼 값을 가져옴
        break;
  • char,bool → int
  • short → int
  • float → double

가변인자 참고 - 1

가변인자 참고 - 2

profile
노는게 젤 조아. 친구들 모여라!!

0개의 댓글