본문 바로가기

프로그래밍/C

[study] 가변인자 (variable argument)

가변인자란?

- 타입과 개수가 정해져있지 않고, 따라서 인자의 개수가 변하는 인자이다.

- C언어에서 대표적으로 printf나 scanf 등의 함수들이 매개변수의 개수가 정해지지 않은 함수이다.

- 함수에서 가변 인자를 정의할 때는 고정 매개변수가 한 개 이상 있어야하고, 해당 고정 매개변수 뒤에

'...' 을 붙여 매개변수의 개수가 정해지지 않았다고 표시한다. 이 '...' 뒤에는 다른 매개변수 지정 불가.

 

가변인자 처리 매크로

pr 이라는 함수에서 ... 으로 들어온 매개변수를 활용하기 위해서는, stdarg.h 에 있는 매크로들을 불러와야 한다.

stdarg.h 에 정의된 가변인자 처리 매크로는 다음과 같다.

 

1. va_list : 가변 인자 목록. 포인터에 가변 인자의 메모리 주소를 저장한다.

2. va_start : 가변 인자를 가져올 수 있게 포인터를 설정해준다.

3. va_arg : 가변 인자 포인터에서 특정 자료형 크기만큼 값을 가져온다.

4. va_end : 가변 인자 처리가 끝나면 포인터를 NULL로 초기화 해준다.

 

활용 예시)

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

void pr(int args, ...)
{
    int     i;
    int     num;
    va_list la;

    va_start(la, args);
    i = 0;
    while (i < args)
    {
        num = va_arg(la, int);
        printf("%d ", num);
        i++;
    }
    va_end(la);
    printf("\n");
}

int main()
{
    pr(1, 1);
    pr(2, 1, 2);
    pr(3, 1, 2, 3);
    pr(4, 1, 2, 3, 4);
    pr(5, 1, 2, 3, 4, 5);

    return (0);
}

 

다음은 예시이다.

함수 정의 시 void pr(int args, ...) 으로 하여, 첫 매개변수인 args에는 가변 인자 개수 받도록 지정하고,

두 번째 매개변수에서 가변 인자 받기 위해 ... 으로 한다.

... 부터는 매개변수로 아무것도 넘겨주지 않거나 여러개를 줄 수 있는 부분이다.

 

이 pr 함수를 호출할 때는 pr(5, 1, 2, 3, 4, 5) 와 같이 처음에 인수 개수를 넣고, 이후 인수 개수에 맞게

콤마로 구분하여 인수를 넣어주면 된다.

 

void pr(int args, ...)
{
    int     i;
    int     num;
    va_list la;

    va_start(la, args);
    i = 0;
    while (i < args)
    {
        num = va_arg(la, int);
        printf("%d ", num);
        i++;
    }
    va_end(la);
    printf("\n");
}

 

이제 pr 함수 내부를 살펴보면, va_ 로 시작하는 변수들이 있는 것을 볼 수 있다.

이 변수들은 가변인자들을 가리켜 인자들을 사용할 수 있게 해주는 매크로들이다. 

 

우선 va_list 는 앞서 언급했듯이, '가변 인자 목록' 인데 이는 가변 인자의 시작 주소를 가리킬 포인터가 된다.

이 포인터는 지금 가리키는 대상이 없으므로, 이 포인터를 가변인자의 첫 부분을 가리키게 하려면 va_start를 이용함.

 

void va_start(va_list arg_ptr, variable_name);

va_start 함수는 va_list로 만들어진 포인터에게 '고정인자'의 주소를 알려주고 va_list의 값을 초기화해준다.

코드를 보면 va_start에 va_list로 만든 arg_ptr 라는 포인터와 variable_name (고정인자)을 알려준다.

이 va_list에 주고 싶은 것은 가변인자 시작 주소이지만, 가변 인수의 갯수를 알 수 있는 첫 고정인자가 필요하다.

따라서 필수로 오는 매개변수인 첫번째 고정인자를 준다. 이를 통해 가변인자에 접근하여 포인터를 초기화한다.

 

var_type va_arg(va_list arg_ptr, var_type);

그리고 위의 va_arg 함수를 사용하는데, 이는 va_list로 저장된 값을 검색해 반환하는데,

var_type 으로 가변 인자의 자료형을 지정해준다.

이 va_arg는 다음 인수를 가리키도록 va_list의 주소를 이동시켜 다음 인수 시작 위치로 변경하며,

(다음 위치로 가는 것은 var_type으로 지정된 자료형만큼이다. int면 4byte만큼 순방향으로 이동)

va_list가 가리키는 값을 var_type으로 캐스팅하여 반환하는 작업을 한다.

(현재 포인터에 해당하는 값을 먼저 가져오고, 포인터를 다음 시작 위치로 변경한다.)

 

void va_end(va_list arg_ptr);

va_end는 가변인자 포인터를 다 사용하고 나서, 해당 포인터의 값을 NULL로 변경하기 위해 사용한다.

 

void va_copy(va_list dest, va_list src);

사용하지는 않았지만 va_start를 dest에 적용하고, dest 위치에 src로 초기화 해주는 va_copy 함수도 있다.

 

마지막으로, main으로 돌아가 실행 결과를 살펴보자.

 

원하는 출력이 잘된 모습을 볼 수 있다.

이처럼 여러 매개인자를 활용하고 싶다면, 가변인자와 매크로들을 이용할 수 있다.

가변인자는 동적으로 인자의 개수를 변경할 수 있다는 점이 가장 핵심적인 부분이다!

'프로그래밍 > C' 카테고리의 다른 글

[library] strncmp 구현하기  (0) 2024.05.10
[library] strrchr 구현하기  (0) 2024.04.16
[library] strchr 구현하기  (0) 2024.03.30
[library] strlcat 구현하기  (2) 2024.03.19
[library] strlcpy 구현하기  (0) 2024.03.19
Recent Posts
Popular Posts
Recent Comments