본문 바로가기
프로그래밍 언어/C, C++의 기본적인 설명

[C 언어] 함수와 가변 전달 인자

by Physics 2022. 3. 26.
728x90

python에서는 함수의 가변인자를 *kwarg를 이용해서 만들 수 있다. C에서도 동일하게 함수의 가변인자를 줄 수 있다. 함수의 가변인자를 정의하는 것은 크게 두 가지 방법으로 나뉜다. 
  a. 가변 전달 인자 매크로 사용 
  b. 헤더 파일 stdarg.h 사용 

1. 가변 전달인자 매크로 (C99)

1) 가변 전달인자 매크로: ...와 __VA_ARGS__ 
  - 매크로 정의 전달인자 리스트의 마지막 전달인자로 생략기호인 "..."를 사용할 수 있음 
  - 생략기호(생략기호: ...)가 사용된 경우, 대체 리스트에서 그것을 대체하는 것을 지정하기 위해 미리 정의된 매크로 __VA_ARGS__를 사용할 수 있음 

2) Appendix 1 참조 

2. 헤더 파일 stdarg.h 사용 

stdarg.h와 가변전달인자 매크로 비교

stdarg.h는 가변전달인자 매크로에 비해 사용하기는 더 까다롭지만, 가변 전달인자 함수는 적용 범위가 훨씬 더 넓다. 

stdarg.h를 이용한 가변인자 정의 절차

1) 생략 기호를 사용하여 함수 프로토타입을 제공 
2) 함수 정의 안에 va_list형 변수를 생성 
3) 그 변수를 전달인자 리스트로 초기화하는 매크로를 사용함 
4) 전달인자 리스트에 접근하는 매크로를 사용 
5) 흔적을 깨끗이 지우는 매크로를 사용 

 

 

 

1. 가변인자 함수 정의 

함수의 정의 

int func(<명시적인 매개변수>, int parmN, ...)

//example 
int f2(const char *s, int k, ...)


- 예시 

double sum(int lim, ...){
	va_list ap; // 전달인자를 담을 매개 변수 
}

 - 변수 lim : parmN 매개 변수 
   -- 가변 전달인자 리스트에 있는 전달인자의 개수를 나타냄 

NOTE 1: va_list형 
- 매개 변수 리스트의 생략 기호 부분에 해당하는 매개 변수를 담는데 사용할 하나의 데이터 객체를 나타냄 

2) 두번째 단계
- stdarg.h에 정의된 va_start() 매크로를 사용하여, 전달인자 리스트를 va_list 변수에 복사함 
- va_start() 매크로는 두 개의 전달인자를 사용함: va_list, parmN

3) 세번재 단계 
- 매크로 va_arg()를 사용하여 전달인자 리스트의 내용에 접근 
- va_arg()의 두 개의 전달인자: va_list형 변수, 데이터형 이름 
   -- NOTE: 반드시 데이터형 전달인자는 실제 지정한 것과 일치해야 함. 데이터형 자동변환은 이루어지지 않음 
- va_arg() 함수를 호출 할 때마다, 그 다음 항목을 리턴함 

NOTE: va_arg는 접근을 한 후, 이전 전달인자로 돌아갈 수 없기 때문에, va_copy()라는 이용해서, 다시 접근을 해야 한다. 

va_list ap;
va_list apcopy;

double tic;
int toc;
...
va_start(ap, lim);        // ap를 전달인자 리스트로 초기화함
va_copy(apcopy, ap);      // ap를 apcopy에 복사함 
tic = va_arg(ap, double); // 첫 번째 전달인자를 얻음
toc = va_arg(ap, int);    // 두 번째 전달인자를 얻음

4) 마지막 단계 
va_end()를 사용하여 전달인자를 담기 위해 사용한 동적으로 할당한 메모리를 해제함 

 

Appendix 1) __VA_ARGS__를 사용한 가변 전달인자의 예시 

 

#include <stdio.h>
#include <math.h>

#define PR(X, ...) printf("Message: #X": __VA_ARGS__)

int main(void){
	double x = 48;
    double y ;
    
    y = sqrt(x);
    
    PR(1, "x = %g\n", x);
    PR(2, "x = %2.f, y = %4.f\n", x, y);
}

1. 첫번째 매크로: PR(1, "x = %g\n", x)
다음과 같이 확장됨

printf("Message 1 : x = %g\n", x)

 

 

 

Appendix 2) stdarg.h를 사용한 가변 전달인자의 예시 

#include <stdio.h>
#include <stdarg.h>

double sum(int, ...);

int main(void){
	double s,t;
    
    t = sum(3, 1.1, 2.5, 13.3);
	s = sum(6, 1.1, 2.1, 13.1, 4.1, 5.1, 6.1);
    
    printf("sum(3, 1.1, 2.5, 13.3): %f\n", t);
    printf("sum(6, 1.1, 2.1, 13.1, 4.1, 5.1, 6.1): %f\n", s);
}

double sum(int lim, ...){
	va_list ap;   // 전달인자를 담을 객체를 선언
    double tot = 0;
    int i;
    
    va_start(ap, lim);	// ap를 담을 전달인자 리스트로 초기화함 
    for (int i = 0; i < lim; i ++){
    	tot += va_arg(ap, double)	// 전달인자 리스트에 있는 각 항목에 접근함 
    }
    va_end(ap);						// 흔적을 깨끗이 지움
    
    return tot;
}

 

Appendix 3) stdarg.h

- stdarg.h 헤더파일은 개수가 가변적인 전달인자를 가지는 함수를 정의하는 수단을 제공함 
- 가변인자를 가지는 함수의 프로토타입은 하나의 매개변수와 뒤에 생략기호(...)가 붙어있는 매개변수 리스트를 가져야 함 

가변 매개변수 리스트 매크로 

해당 헤더 파일은 매개변수 리스트의 생략부분에 해당하는 매개변수들을 저장할 데이터 객체들을 나타내기  위해 va_list형을 선언한다. 

프로토 타입 설명
void va_start(va_list ap, paramN) 이 매크로는 va_arg()와 va_end()가 사용하기 전에 미리  ap를 초기화한다. parmN은 매개변수 리스트에 있는 이름이 지정된 마지막 매개변수를 나타내는 식별자이다.
void va_copy(va_list dest, va_list src) 이 매크로는 src의 현재 상태의 사본으로  dest를 초기화한다.
type va_arg(va_list ap, type) 이 매크로는 ap로 나타낸 매개변수 리스트에 들어 있는 다음 항목과 동일한 값과 데이터형을 가지는 수식으로 확장한다. type은 그 항목을 나타내는 데이터형이다. 각 호출은 ap에 엤는 다음 항목으로 진행한다.
void va_end(va_list ap) 이 매크로는 이 처리를 끝내고 va_start()가 다시 호출될 때까지 ap를 사용할 수 없는 상태로 만든다. 
728x90

댓글