2010년 11월 8일 월요일

C언어 - 가변인자 사용(pritnf 같은 함수를 만들자!!)

printf() 함수는 참 신기 합니다.

printf("정수? %d, 문자열? %s", 5, "문자열이긔");

인자가 3개네요.

printf("실수? %f, 문자열? %s, 정수? %d", 3.14, "문자열이긔", 7);

이번엔 또 인자가 4개군요.

C언어에서는 함수의 오버로딩을 지원 하지 않습니다.
결국 원형은 하나라는 건데..
그럼 printf()함수는 원형이 어떻게 생겼을까요?

#include <stdio.h>

비밀은 여기에 있습니다.
우리가  printf 함수를 쓰면서 당연히 인클루드 하던 stdio.h
 파일 열어 보신  있으신가요?
한번 열어서 printf()함수를 찾아 봅시다.

_Check_return_opt_ _CRTIMP int __cdecl printf(_In_z_ _Printf_format_string_ const char * _Format, ...);

웁스;;
이건 암호도 아니고;;;; 별 도움이 않되겠네요;;
오히려 헷갈리는 --;;

그럼 모르는 것 빼버리고 우리가 알고 있는 함수 처럼 만들어 봅시다.

int printf(const char * _Format, ...);

그래도 모르는게 하나 남았네요.

...

장난 하나요? 무슨 쓰기 싫어서 ... 으로 생략 했나 봅니다.
는 아니고 사실 비밀은 저 ...에 있습니다.
우리가 아는 그대로 나머지 인자는 여러개가 있을 수 있다는 이야기 입니다.

아하 그럼 우리도 함수를 저렇게 선언하면 가변적인 인자에도 대응 할 수 있겠군요?
네 그렇습니다.

자 함수 하나 만들어 보죠~

그전에 메인 함수 부터 만들어 보죠.

int main()
{
     vaFunc(3, "Hello", "World", "!!!");

     return 0;
}

vaFunc() 라는 함수가 가변적으로 인자를 받는 함수입니다.
그럼 선언은

int vaFunc(int argc, ...)

뭐 이렇게 하면 되겠죠?
다음 vaFunc() 함수의 몸체를 써내려가야 하는데...
argc는 쓸 수 있는데 그 다음 부터는 어떻게 하죠?

자 여기서 쓰는것이 va_list 라는 것입니다.

va_list 및 가변 인자에 관한 것은 <stdarg.h> 파일에 정의 되어 있습니다.

#include <stdarg.h>

하시고,

int vaFunc(int argc, ...)
{
     va_list argptr;
     char *strTemp;
     int i;
     va_start(argptr, argc);

     for(i = 0; i < argc; ++i)
    {
          strTemp =  va_arg(argptr, char *);
          printf("Arg %d = %s\n", i, strTemp);
     }
  
     va_end(argptr);
  
     return 0;
}

내용물을 체웁시다.

눈썰미 있는 분은 코드만 봐도 아시겠네요.

먼저

va_list argptr;

가변인자를 처리하기 변수를 선언 합니다.

va_start(argptr, argc);

다음으로 가변인자가 시작될 위치를 지정하죠.
우리가 만든 함수와 printf() 는 고정 부분이 하나지만
여러개가 올 수도 있답니다.

vaFunx(int arg1, float arg2, ...);

등으로 말이죠.
위의 경우는

va_start(argptr, arg2);

로 해줘야 합니다.
가변인자는 arg2 다음에 오니 말이죠 ㅎㅎ

strTemp  = va_arg(argptr, char *);

가변인자의 인자를 하나씩 strTemp 에 대입해 줍니다.
"Hello", "World", "!!!" 순으로 말이죠.

눈치 체신분도 있으실텐데...
가변인자는 인자의 갯수를 알 수 있는 수단을 제공해야 합니다.
그래서 처음 인자를 뒤의 인자의 갯수로 써주는 것입니다.
그럼 printf()의 경우는??

printf("Arg %d = %s\n", i, strTemp);

를 보시면 삘이 확 오시나요?
그렇습니다.
%d, %s 이런것을 보면 뒤에 오는 인자의 갯수를 알 수 있답니다.
조심해야 할점은 뒤의 인자의 갯수는 모자라면 않된다는 점입니다.
메모리 접근 위반이 나겠죠?
또한 인자의 타입도 달라서는 않됩니다.

마지막으로

va_end(argptr);

내부적으로 초기화를 수행해 완료 작업을 합니다.
메모리 누수가 발생할 수도 있으니 빼먹지 맙시다.

이것으로 우리도 가변인자를 지원하는 함수를 만들 수 있겠네요~

댓글 없음:

댓글 쓰기