C 언어 가변인자 사용법
#include <stdarg.h> 에서 가변인자 관련 매크로를 가져와서 사용한다.
#include <stdarg.h>
void printNumbers(int argc, ...) // 가변 인자의 개수를 받음, ...로 가변 인자 설정
{
va_list ap; // 가변 인자 목록 포인터
va_start(ap, argc); // 가변 인자 목록 포인터 설정
for (int i = 0; i < argc; i++) // 가변 인자 개수만큼 반복
{
int num = va_arg(ap, int); // int 크기만큼 가변 인자 목록 포인터에서 값을 가져옴
// ap를 int 크기만큼 순방향으로 이동
printf("%d ", num); // 가변 인자 값 출력
}
va_end(ap); // 가변 인자 목록 포인터를 NULL로 초기화
printf("\n"); // 줄바꿈
}
va_list : char * 형 데이터이며 va_start매크로로 전달받은 인자의 주소 값을 세팅할 수 있다.
char*형인 이유는 문자열 주소이기 때문이 아니라 1byte씩 접근하기 위해서이다.
va_start : va_list에 주소값을 세팅해주는 매크로.
가변인자함수에 인자를 전달할때 스택에 push하는 느낌으로 전달한다. (x8에 sp를 넣고 파라미터값을 가져와 store하는 방식)
adrp는 시작 메모리 주소에서 값을 계산해서 가져온다. 0이 전달돼서 시작메모리주소(0x100003000)를 가져오고 add연산을통해 2번째 인자인 "test"의 주소를 가져온다.
va_start의 역할은 함수 호출직전에 push해둔 인자들의 시작위치를 va_list에 저장하는것이다.
그렇기 때문에 argc가 잘못된 값이 오더라도 값 세팅은 이미 완료된 상태이며 va_arg또한 에러없이 사용 가능하다.
va값을 전달받은 첫번쨰 인자인 argc의 주소를 기준으로 다음 인자의 주소를 세팅해주는 매크로이다.
test_pf(2, 5, "test", 7, 'c');
int test_pf(int argc, ...)
{
va_start(va, argc);
}
va_arg : 8byte단위로 값이 저장된 va_list 변수에서 전달받은 자료형 크기만큼 값을 가져와 반환하고 va_list변수에는 +8을 한다.
w11 레지스터는 4byte 짜리 레지스터이며, ldrb 명령은 byte만 가져온다는 뜻이다.
va_arg(ap, char);
64비트 시스템에서 long은 8byte이기 때문에 x9레지스터에 저장되며 ldr명령으로 가져온다.
va_arg(ap, long);
다른 함수에서 va_arg를 사용할땐 va_list *형으로 받아서 써야한다.
va_list가 포인터형이지만, 더블포인터를 사용하지 않으면 함수 안에서 매크로 호출 시 복사된 주소값만 +8이 되고, 실제 va_start해준 변수의 값은 변하지 않는다.
int func1(int argc, ...)
{
va_list va;
va_start(va, argc)
func2(&va)
va_end(va);
}
int func2(va_list *va)
{
int num = va_arg(va, int);
}