본문 바로가기
프로그래밍 언어/C언어

가변 인자에 대하여

by seongjko 2023. 7. 4.
728x90

가변인자란 인자의 갯수가 정해지지 않은 인자를 의미한다.

가변 인자를 갖는 함수 프로토타입을 선언할 때는 

최소 1개 이상의 고정 인수가 있어야 하고, 가변 인자를 나타내는 '...'은 파라미터 순서상 맨 마지막에 위치해야 한다.

int sum(int count, ...)
{
    int res = 0;
    va_list ap;
    int i;

    va_start(ap, count);
    
    for(i=0; i<count; i++)
        res += va_arg(ap, int);

    va_end(ap);

    return res;
}

int main()
{
    printf("%d\n", sum(10, 1,2,3,4,5,6,7,8,9,10));

    return 0;
}

가변 인자는 va_list, va_start, va_arg, va_end 총 4개의 매크로 함수를 이용해 사용할 수 있다.

 

1. va_list

가변 인자도 데이터이므로 저장할 수 있는 공간이 필요한데 va_list가 이 공간의 역할을 한다.

int 자료형이 int형 데이터를 저장하듯, va_list는 가변 인자를 저장하는 일종의 자료형이라고 생각하면 된다.

위의 코드블럭에서 res를 int형 변수라고 설명할 수 있는 것처럼 ap는 va_list형 변수라고 설명할 수 있다.

내부적으로는 char *로 선언되어 있는 것이 특징이다. 

 

2. va_start

va_list 타입의 변수를 처음 선언하고 나면 그 변수 안에는 아무것도 들어있지 않다.

이때 va_start가 이 변수를 가변인자 중 첫 번째 인자의 주소로 초기화하는 역할을 한다.

va_start는 아래와 같이 정의되어 있다.

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

이 코드를 이해하려면 고정인수와 가변인자의 위치에 대해 아주 약간의 배경 지식이 필요하다.

진짜 별거 아니다.

위의 코드에서 설정한 count라는 고정 인수와 가변 인자는 메모리 상에 이렇게 저장되어 있다.

따라서 count의 주소값에 count의 size만큼을 더해주면 첫 번째 가변 인자의 주소가 ap에 저장될 수 있는 것이다. 

 

3. va_arg

앞서 설명한 요소들과는 달리 특이하게도 2가지 역할을 한다.

1. ap가 다음 순서의 가변 인자를 가리키도록 함

2. 현재 ap가 가리키고 있는 가변 인자를 리턴

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

언뜻 보면 뭔가 복잡해 보이지만 차근차근 나눠서 생각하면 전혀 어려울 것이 없다.

 

ap += _INTSIZEOF(t) -> 이 부분은 ap 안의 주소값을 t만큼 증가시켜서 ap가 다음 가변인자를 가리키도록 하는 게 목적

ap += _INTSIZEOF(t) - _INTSIZEOF(t) -> 이 부분은 현재 ap가 가리키는 가변 인자를 리턴하는 게 목적 

 

4. va_end

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

위와 같이 정의되어 있으며 ap의 내부를 널 포인터로 바꿔주는 역할을 한다.

반응형

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

유효 숫자  (0) 2023.06.26
알면 알수록 헷갈리는 포인터 뽀개기  (0) 2023.06.25