[C++] 함수 사용법(가변 파라미터 stdarg.h, 함수 포인터 그리고 범용 포인터 void*)


Study/C , C++ , MFC  2020. 3. 15. 02:30

안녕하세요. 명월입니다.


이 글은 C++에서 함수 사용법(가변 파라미터 stdarg.h, 함수 포인터 그리고 범용 포인터 void*)에 대한 글입니다.


C++이라고 함수 사용법이 특별한 건 없습니다.

일반 (반환 자료형) (함수명) (파라미터) 순으로 선언이 가능하빈다.

#include <stdio.h>
// 가변 파라미터를 사용하기 위한 함수.
#include <stdarg.h>
#include <iostream>
using namespace std;
// 일반 함수 
// void는 반환 값이 필요없다.
void function(const char* val)
{
  // 콘솔 출력
  cout << " print function " << endl;
}
// 파라미터 값을 합산 함수
// 첫번째 파라미터는 가변 파라미터 개수, ...은 가변 파라미터.
int sum(int count, ...)
{
  // 반환 값 변수
  int ret = 0;
  // 가변 파라미터를 사용할 포인터
  va_list args;
  // va_list가 가변 파라미터의 시작 포인터를 찾고, size를 할당한다.
  va_start(args, count);
  // 가변 파라미터 개수만큼 반복 루프를 돌린다.
  for (int i = 0; i < count; i++) 
  {
    // 가변 파라미터로 부터 값을 취득
    ret += va_arg(args, int);
  }
  // 가변 파라미터 포인터 초기화
  va_end(args);
  // 가변 파라미터 값을 전부 더한 후 반환
  return ret;
}
// 실행 함수
int main()
{
  // 함수 호출..
  function(" hello world ");
  // 합산 함수, 첫번째 파라미터는 가변 파라미터 개수, 그리고 그 다음은 함산할 값.
  int data = sum(10 ,1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
  // 1부터 10까지 더하면 값은 55
  cout << " sum : " << data;
  return 0;
}

일반 함수 호출은 다른 java와 C#과 크게 다른게 없습니다.

C++에서 배열은 그 길이를 알 수가 없습니다. 이유는 포인터로 그 값을 받는데, 포인터는 단순히 포인터의 주소값이지 그 크기를 알 수는 없습니다.

그래서 가변 파라미터를 받게 되면 첫 파라미터를 파라미터의 개수를 넣어야 합니다.


c++에서는 함수를 변수로 담아서 사용할 수 있습니다. python이나 javascript에서 함수를 변수(object)하는 방법과 비슷하고, C#에서 델리게이트와 같습니다.

#include <stdio.h>
#include <iostream>
using namespace std;
// 함수
void function1()
{
  // 콘솔 출력
  cout << " call function - 1 " << endl;
}
// 함수
void function2()
{
  // 콘솔 출력
  cout << " call function - 2 " << endl;
}
// 실행 함수
int main()
{
  // 함수 포인터 선언은 일반 변수 선언과 조금 차이가 있다.
  // fp의 변수명에 함수 포인터 선언 (리턴값은 void이고, 파라미터는 없는 함수)
  void (*fp) ();
  // 함수 포인터에 function1함수를 대입
  fp = function1;
  // " call function - 1 "이 출력
  fp();
  // 함수 포인터에 function2함수를 대입
  fp = function2;
  // " call function - 2 "이 출력
  fp();

  return 0;
}

c++에서는 다른 언어와 다르게 포인터란 존재가 있습니다. 포인터는 메모리의 주소값을 나타내는 int형 데이터입니다.

링크 - https://nowonbun.tistory.com/716 [C++] 배열과 포인터(메모리 주소) 그리고 할당(new){stack과 heap에 대해서}


즉, 포인터 자체의 데이터 사이즈는 4byte입니다.


근데, 포인터는 다른 언어처럼 그 데이터 타입을 표현하는 데이터 타입으로 설정합니다.

#include <stdio.h>
#include <iostream>
using namespace std;
// 실행 함수
int main()
{
  // ptr1에 int형 데이터를 선언
  int* ptr1 = new int();
  // 값 10을 대입
  *ptr1 = 10;
  // ptr2에 char형 데이터를 선언
  char* ptr2 = new char();
  // 값 'a'을 대입
  *ptr2 = 'a';
  // 콘솔 출력
  cout << " ptr1 포인터 값 : " << (int)ptr1 << " 값 :  " << *ptr1 << endl;
  cout << " ptr2 포인터 값 : " << (int)ptr2 << " 값 :  " << *ptr2 << endl;
  // 메모리 해제
  delete ptr1;
  delete ptr2;
  
  return 0;
}

위처럼 int형을 할당하면 int*로 char형을 할당하면 char*형을 선언해서 사용해야 합니다. 그런데 이게 불명확할 떄가 있습니다.

#include <stdio.h>
#include <iostream>
using namespace std;
// 파라미터가 true면 int형 값이 리턴되고, false 면 char형이 리턴된다.
void* function(bool param)
{
  // param이 true면,
  if (param)
  {
    // int형 값을 선언한다.
    int* ptr = new int();
    // 값 10을 넣는다.
    *ptr = 10;
    // 리턴
    return ptr;
  }
  // param이 false이면,
  else
  {
    // char형 값을 선언한다.
    char* ptr = new char();
    // 값 'a'를 넣는다.
    *ptr = 'a';
    // 리턴
    return ptr;
  }
}
// 실행 함수
int main()
{
  // 함수에 true를 넣으면 int*형 데이터가 나온다.
  int* ptr1 = (int*)function(true);
  // 함수에 false를 넣으면 char*형 데이터가 나온다.
  char* ptr2 = (char*)function(false);
  // 콘솔 출력
  cout << " ptr1 포인터 값 : " << (int)ptr1 << " 값 :  " << *ptr1 << endl;
  cout << " ptr2 포인터 값 : " << (int)ptr2 << " 값 :  " << *ptr2 << endl;
  // 메모리 해제
  delete ptr1;
  delete ptr2;

  return 0;
}

void*형 타입은 정해지지 않는 데이터 타입의 포인터를 받을 수 있습니다. 어차피 포인터는 주소 값이고 int형 타입의 4byte입니다.

데이터 타입은 크게 중요하지 않기 때문에 그냥 포인터값이면 전부 void*로 받아도 상관 없습니다.

c++ 프로젝트가 커지고 MFC에서 포인터를 윈도우 메시지에 올리고, 포인터 값을 이리 던지고 저리 던지고 할때 이 자료형을 명시하지 않으면 나중에 값의 데이터 타입을 알 수가 없어지기 때문에 형식적으로라도 정확한 타입으로 설정하는게 좋습니다.


여기까지 C++에서 함수 사용법(가변 파라미터 stdarg.h, 함수 포인터 그리고 범용 포인터 void*)에 대한 글이었습니다.


궁금한 점이나 잘못된 점이 있으면 댓글 부탁드립니다.