의미
가변인자 함수는 인자의 개수가 정해지지 않은 함수를 의미한다. 예를들면 printf, scanf 함수가 가변인자 함수이다.
int printf(const char*, ...);
int scanf(const char*, ...);
동작 방식
상황에 따라 들어오는 인자의 개수가 다르므로 <stdarg.h>에 정의 되어있는 함수를 이용해서 다룬다.
1. va_list args
- 가변 인자 목록, 가변 인자의 메모리 주소를 저장하는 포인터이다.
- va_list : char *형
- args : argument를 가리키는 포인터
2. va_start(args, 마지막 고정인수)
- 가변 인자를 가져올 수 있도록 포인터를 설정한다.
3. va_arg(args, type)
- 가변 인자 포인터에서 특정 자료형 크기만큼을 가져온다.
4. va_end(args)
- 가변 인수를 읽은 후 뒷처리를 해주어야할 필요가 있으므로 관례적으로 호출하는 것이 좋다.
예제 1. 함수 작성자와 사용자간에 규칙을 정하고 그 규칙에 의해서만 사용해야한다.
출력을 예상해보기
#include <stdio.h>
#include <stdarg.h>
enum {va_eol = -1};
double average(int first, ...);
int main()
{
double res;
res = average(10,30,va_eol);
printf("res = %.2lf\n", res);
res = average(-7, -5, -1, 1, 5 ,7, va_eol);
printf("res = %.2lf\n", res);
return 0;
}
double average(int first, ...)
{
unsigned int count = 0;
unsigned int sum = 0;
int i = first;
va_list args;
va_start(args, first);
while(i != va_eol)
{
sum += i;
count++;
i = va_arg(args, int);
}
va_end(args);
return (count ? (double)sum/count : 0);
}
출력 :
res = 20.00
res = 2147483642.00
위 코드를 보면서 va_list, va_start, va_arg, va_end를 사용하는 방법을 확인한다. 두번째 res의 출력이 2147483642.00 으로 나온 이유는 int 형이 unsinged int 형으로 타입캐스팅 되면서 일어난 결과 이고 이 부분에 대해서는 이후 타입 캐스팅 관련 취약성에 대한 설명에서 자세히 다룬다.
POINT
- 함수 작성자와 사용자간에 규칙을 정하고 그 규칙에 의해서만 사용해야한다.
- 가변 인자를 제어하기 위해서는 va_list, va_start, va_arg, va_end 함수를 이용해서 제어한다.
참조
DCL10-C. Maintain the contract between the writer and caller of variadic functions
wiki.sei.cmu.edu/confluence/display/c/PRE00-C.+Prefer+inline+or+static+functions+to+function-like+macroswiki.sei.cmu.edu/confluence/display/c/PRE06-C.+Enclose+header+files+in+an+include+guardwiki.sei.cmu.edu/confluence/display/c/PRE10-C.+Wrap+multistatement+macros+in+a+do-while+loopwiki.sei.cmu.edu/confluence/display/c/DCL10-C.+Maintain+the+contract+between+the+writer+and+caller+of+variadic+functions
'C, C++ > 선언과 초기화' 카테고리의 다른 글
[CERT C/선언과 초기화] (3) 기억클래스 취약성 (0) | 2021.01.23 |
---|---|
[CERT C/선언과 초기화] (1) 코드의 가독성을 높이기 위해 타입 정의를 사용하라 (0) | 2021.01.22 |