티스토리 뷰

Programming/C++

C/C++ - 가변인자 ...

글그리 2016. 11. 19. 10:08

개요


C 또는 C++언어에서 함수의 매개변수를 가변적으로 전달하고자 하는 경우가 있다.

그 경우의 수가 많지 않거나 가변적이지 않을 때는 함수 오버로딩으로 작성하여 해결할 수 있다.


함수의 매개변수로 int변수를 2~4개 받아야할 경우


void PrintInt(int a, int b);
void PrintInt(int a, int b, int c);
void PrintInt(int a, int b, int c, int d);


하지만 printf 또는 scanf 같은 함수처럼 몇개의 매개변수를 넘길지 그 경우가 가변적일 경우 가변인자를 사용한다.






가변인자


가변인자는 ...으로 받을 수 있으며, ...에 전달된 매개변수들은 va_list로 저장되어 있고, va_list포인터로 접근할 수 있다. 함수로 전달되는 매개변수 list의 포인터를 생성하고 포인터로 list를 읽어서 값을 가져올 수 있다.

가변인자에 접근하기 위해서 다음 자료형과 함수를 사용한다.


va_list

전달받은 가변인자 list를 가리키는 포인터



va_start()

va_list가 특정 위치를 가리키게 한다.



va_arg()

va_list가 가리키는 위치부터 자료형 크기만큼 데이터를 읽어서 반환한다.



va_end()

va_list가 가변인자 list 시작을 가리키게 한다.




사용 방법


실제 사용하는 코드를 보며 더 자세히 알아보자. 다음은 가변인자를 가리키는 argptr을 생성해서 매개 변수 a 다음(즉, 가변인자 list의 시작지점)을 가리키게 한 후 int 정수 하나를 읽어서 b에 저장하는 코드이다.


void PrintVarioublnt(int a, ...){
va_list argptr;
va_start(argptr, a);

int b = va_arg(argptr, int);

va_end();
}





사용 방법 2


기본적으로 첫번째 매개변수에 전달되는 매개변수 list의 갯수를 넘겨줘서 함수 내부에서 처리할 수 있도록 하는 방법이 있다.


void PrintVarioubleInt(int count, ...){
va_list argptr;
va_start(argptr, count);

for(int i=0; i<count; i++)
cout<<va_arg(argptr, int)<<" ";

va_end();
}

void main(){
PrintVarioubleInt(3, 1, 2, 3);
// >1 2 3
}





응용 : cocos2d-x


cocos2d-x의 sequence클래스의 경우 특별한 규칙을 설정해 사용자로 하여금 전달할 매개변수를 일일이 세서 그 count를 전달할 필요가 없도록 만들었다.

정확한 엔진의 코드는 아니지만 대략적인 sequence 클래스의 객체 생성 방법은 다음과 같다.

// Sequence

// moveto moveby 같은 action들을 순차적으로 실행시키는 action으로, 실행시킬 action들을 전달하면 전달받은 action들을 이어 붙여서 하나의 action으로 만든다.


Sequence* Sequence::create(Action* act1, ...){
va_list param;
va_start(param, act1);

Sequence* seq = createVarioubleList(act1, param);

va_end();
return seq;
}

Sequence* Sequence::createVarioubleList(Action* act, va_list param){
Action* prev = act;
Action* now;
while(act){
now = va_arg(param, Action*);
if(now != NULL)
prev = Sequence::createPair(prev, now);
else
break;
}
return (Sequence*)prev;
}

Sequence Sequence::createPair(Action* act1, Action* act2){
Sequence* seq = new Sequence(act1, act2);
return seq;
}


위 코드에서 createVarioubleList() 의 if(now != NULL)부분을 보자.

va_arg는 list가 끝났는지 검사하지 않고 그저 포인터를 하나 증가시키면서 가장 앞에있던 자료를 반환하기 때문에 list가 끝나도 쓰레기값을 반환할 뿐 특별한 조치를 하기가 어렵다.

cocos2d 엔진은 Sequence::create()를 호출할 때 마지막 매개변수로 NULL을 입력하는 규칙을 만들어서 이 문제를 해결했다.

매개변수 list의 마지막 값은 항상 null이라고 가정하면 now에 NULL값이 반환되어 왔을 때 그것을 list의 마지막이라고 생각하고 처리할 수 있다.


'Programming > C++' 카테고리의 다른 글

C/C++ - sscanf, sscanf_s  (0) 2017.01.23
C/C++ - assert  (0) 2016.12.28
namespace 활용하기  (2) 2016.10.10
동적할당한 stl::list 해제하기  (0) 2016.09.11
함수 콜 성능을 향상시키자 - #pragma intrinsic  (0) 2016.03.20
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함