printf( ) 함수의 경우
printf("Helle World\n"); 라고 쓰면 인자가 1개 이다.
printf("%d\n", 10); 라고 쓰면 인자가 2개 이다.
printf("%d, %d\n", 10, 20); 라고 쓰면 인자가 3개이다.
이런식으로 인자가 변하는 함수는 어떻게 구현 되어있을까?
또는 어떻게 구현할 수 있을까?
먼저....
#include <stdio.h>
// args는 고정 매개변수
void printfMy(int args, ...)
{
printf("%d ", args);
}
int main()
{
printfMy(1, 10);
printfMy(2, 10, 20);
printfMy(3, 10, 20, 30);
printfMy(4, 10, 20, 30, 40);
return 0;
}
이와 같이 했을 때 ... 은 인자가 가변이라는 뜻이다.
하지만 실행 결과 1,2,3,4 즉, args 만 출력이 되었다.
가변인자의 값을 출력하려면 어떻게 해야 할까?
#include <stdio.h>
#include <stdarg.h> // va_list, va_start, va_arg, va_end 를 사용하기 위해서
void printfMy(int args, ...)
{
va_list ap;
va_start(ap, args);
for (int i = 0; i < args; i++)
{
int num = va_arg(ap, int);
printf("%d ", num);
}
va_end(ap);
printf("\n");
}
int main()
{
printfMy(1, 10);
printfMy(2, 10, 20);
printfMy(3, 10, 20, 30);
printfMy(4, 10, 20, 30, 40);
return 0;
}
// 결과
// 10
// 10 20
// 10 20 30
// 10 20 30 40
va_list ap
va_start( ) 함수의 첫번째 인자로 argument pointer 가 들어간다.
여기에서 argument pointer 는 va_list ap; 즉, ap 이다.
이 ap 는 인자로 들어온 여러개의 값이 배열과 같이 연달아 있는 메모리의 첫 시작 주소가
va_start( ) 함수에 의해 얻어진다.
(ap 는 관례적으로 ap 라고 쓰며 char* 로 정의되어 있다.)
va_start(ap, 마지막고정인수)
va_start( ) 함수에는 반드시 고정인수가 들어가야 한다.(두번째 인자로 들어감)
printfMy(고정인수, ...);
printfMy 함수의 첫번째 인수가 고정인수인데,
va_start( ) 함수는 이 고정인수의 주소를 이용하여 첫 가변인수의 주소를 구하기 때문이다.
참고)
고정인수가 여러개일경우에는 마지막 고정인수가 들어가야 한다.
prinfgMy(고정인수1, 고정인수2, ...)
va_arg(ap, 인수타입)
va_arg( ); 함수는 실제로 가변인수를 얻어오는 함수인데,
va_start( ) 함수가 첫번째 가변인수의 주소를 ap 에 구해 놓았으니,
우리는 va_arg 를 이용하여 읽어들이면 된다.
예를들어 ap 위치에 있는 정수를 읽고 싶으면 va_arg(ap, int) 를 호출하고
실수를 읽고 싶으면 va_arg(ap, double) 을 호출하면 된다.
이 함수는 ap 의 위치를 자료형타입에 맞게 읽어 주고 리턴해주며,
또한 ap 를 다음 가변인수의 주소로 옮겨준다.
va_end(ap)
이 함수는 ap 의 값을 초기화 해준다. 아니, 실제로는 아무런 동작을 하지 않는다.
플랫폼에 따라서 가변인수를 읽은 후에 초기화 해주는 필요가 있을 수 있고,
관례적으로 사용하긴 하는데, 적어도 인텔 계열의 CPU 에서는 아무것도 하지 않는다.
그러나 미래에 어떻게 바뀔지 모르니, 넣어주는것이 옳다고 생각한다.
#include <stdio.h>
#include <stdarg.h> // va_list, va_start, va_arg, va_end 를 사용하기 위해서
void printfMy(const char* types, ...)
{
va_list ap;
int i = 0;
va_start(ap, types);
while (types[i] != '\0') // 문자열의 끝 '\0' 이면 while 문을 벗어남
{
switch (types[i])
{
case 'd':
printf("%d ", va_arg(ap, int));
break;
case 'f':
printf("%f ", va_arg(ap, double));
break;
case 'c':
printf("%c ", va_arg(ap, char));
break;
case 's':
printf("%s ", va_arg(ap, char*));
break;
default:
break;
}
i++;
}
va_end(ap);
printf("\n");
}
int main()
{
printfMy("sdfc", "Hello World", 30, 102.86f, 'a');
return 0;
}
printfMy 함수에서 " " 내부의
s 자리에 "Hello World를
d 자리에 30을
f 자리에 102.86f을
c 자리에 'a' 를 출력할 수 있도록 하였다.
참고) GCC 의 경우
char,bool,short 은
va_arg(ap, int);
float 는
va_arg(ap, double)
로 읽어야 한다.
'C언어(2020년)' 카테고리의 다른 글
28. union (0) | 2020.11.04 |
---|---|
27. 전처리기 (0) | 2020.11.04 |
25. Call by Value, Call by reference, Call by Address (0) | 2020.11.04 |
24. 함수 (0) | 2020.11.04 |
23. define (0) | 2020.11.04 |