가변인자란?
- 타입과 개수가 정해져있지 않고, 따라서 인자의 개수가 변하는 인자이다.
- 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 |