안녕하세요. va_start, va_arg 가 갯수를 알 수없는 "..." 에 해당하는 인자를 받아오는 것입니다.. 그런데 va_arg를 사용하지 않고 구현하신다고요? 그러면 va_arg가 하는일을 직접 구현해야 겠지요. %d만을 사용한다면 굉장히 간단해 집니다.
va_arg를 구현하기 위해서는 C 가 함수 호출전 파라미터를 전달하는 방식을 알면 간단합니다. printf 함수 호출전 함수에 전달되는 파라미터들을 뒤에서 부터 차례대로 스택에 넣습니다.
printf(buf, 1, 2, 3); 이라면 3, 2, 1, buf주소 순으로 push됩니다. 그러면 스택은 아래와 같겠죠? (16bit 환경이라 가정하고 스택이 0xFFFF부터 시작)
0xFFF9 buf주소
0xFFFB 1
0xFFFD 2
0xFFFF 3
그럼 buf의 주소를 이용해 파라미터를 차례대로 알 수 있습니다. C에서 포인터를 사용해서 한다면...
testfunc(char *buf, ...)
{
int *p;
p = (int *) &buf; // 스택상 buf의 위치를 p에 넣습니다.
printf("%d\n", *(p+1)); // 1이 출력됩니다.
printf("%d\n", *(p+2)); // 2가 출력됩니다.
p에 스택상 buf의 주소를 대입시킵니다. p+1을 하면 p가 integer 포인터이기 때문에 16bit상에서 2bytes가 증가하게 됩니다. 그래서 0xFFFB 위치의 값 1을 가리킵니다.
위와 같이 buf의 주소로 buf 다음에 오는 파라미터가 몇개인던지간에 가져올 수 있습니다. 파라미터 수보다 %d가 더 많으면 push된 파라미터들 이상의 메모리를 가리켜 메모리 오류가 나겠죠?
va_arg도 위와 같은 방식으로 이루어집니다. 그리고 실제로 Borland C++ 내에 구현된 vsprintf도 위와 같은 방식으로 va_arg를 사용해 구현된 것입니다. Borland C++ 에 있는 printf를 가지고 %d를 더많게 해보시면 똑같이 메모리 오류가 나는것을 보실 수 있습니다.
도움이 되시길 바랍니다.
|