본문 바로가기

CS/C

Variadic is

가변인수.

함수는 인자 개수를 고정하지 않고 가변으로 사용할 수 있다.


1. 가변 인수를 사용하려면 stdarg.h 헤더 파일을 첨부해야한다.

※stdarg.h 의 정의

typedef struct{

char *a0; //첫 번째 인자를 가리키는 포인터

int offset; //다음 매개변수의 바이트 단위의 변위(offset)

}va_list;


2. 가변 인수 내부구조.

1) va_list

구조체로 가변 인자의 내부 상태를 저장한다.

stack에 저장되며 함수는 stack에서 인수를 꺼내 쓴다.(stack에서 읽을 때 포인터 연산을 해야한다.)

∴현재 읽고 있는 번지를 기억하기 위해 va_list형의 포인터 변수 하나가 필요하다.

2) va_start(va_list arg, parmN v)

가변 인수 arg를 사용하기 위해 void *포인터로 초기화한다.

parmN은 매개변수 리스트에 있는 이름이 지정된 마지막 매개변수를 나타내는 식별자이다.

(첫 번째 가변 인수의 번지를 조사하기 위해 마지막 고정 인수를 전달.)

※va_start 내부에서는 va_list arg(ap)가 마지막 고정 인수 다음 번지를 가리키도록 해주므로, 이후부터  va_list arg 번지를 

(arg는 지역변수 일 뿐, 아무거나 써도 좋다.

관습적으로 간변 인수를 다루는 매크로에서는 ap(Argument Pointer)를 사용한다.)

읽으면 순서대로 가변인수를 읽을 수 있다.


3) va_arg(va_list arg, type t)

가변 인자 arg를 정의한 type t로 가져온다.

가변 인수를 읽는 실제 명령.

va_start가 va_list arg를 첫 전째 가변 인수 번지로 맞춰 주므로 va_list arg 위치에 있는 값을 읽기만 하면 된다.

va_list arg 번지에 있는 값이 어떤 type인지 알 수 있도록 두 번째 인수에 타입 지정을 해줘야한다.

(return 값은 인수 타입에 맞는 변수로 대입해줘야한다.)

va_list arg 위치에서 타입에 맞는 값을 읽어 return 하며 또한 va_list arg를 다음 가변 인수 위치로 옮겨준다.

∴va_arg를 반복적으로 호출하면 전달된 가변 인수를 순서대로 읽을 수 있다.

tip)

타입명은 함수의 인수가 될 수 없다.

이것은 매크로 함수이므로 가능하다.

(va_arg 두 번째 인수는 내부적으로 size of 연산자와 캐스트 연산자로 전달되기 때문에 가능)

4) va_end(va_list arg)

사용하는 가변 인수 arg를 정의한 type t로 가져온다.

인텔은 필요없다, 다른 플랫폼/미래 환경에서는 호환성을 위해 필수.


3. 프린트문

int printf(const char *format, ...)

1) format 

첫 번째 인수, 문자열 상수(서식 문자열)

(printf의 첫 번째 인수는 const char 이므로 반드시 서식 문자열이어야한다.

 ∴정수 하나 출력시 printf("%d", i) 로 출력한다.)

2) ...(생략 기호)

두 번째 인수 이후,

컴파일러는 ...이후의 인수에 대해서 개수가 몇개이든 어떤 타입이든 상관하지 않고, 있는 그대로 함수에게 넘기므로 상관없이 전달 가능.

but! 함수가 알아서 판별해 사용해야 한다.


※ vprintf() 함수는 printf()함수와 유사하다.

vfprintf(FILE *stream, const char *format, va_list arg);

vsprintf(const char *buf, const char *format, va_list arg);


4. 예제

5+7과 4+5+6의 덧셈 결과를 출력하기 위해 리턴값이 있고 가변의 매개변수를 갖는 덧셈 함수와 메시지를 출력하는 함수를 정의하고 사용하는 방법을 보여준다.




참고 자료 : 예제로 쉽게 풀어 쓴 C기초 프로그래밍.

'CS > C' 카테고리의 다른 글

What is pointer?  (0) 2012.10.27