함수 포인터 기본 사용법과 간단한 활용 예를 알아보자. 예제는 C++, C에서도 동일하게 사용 가능하다.
1. 함수 포인터 기본 사용법
함수 포인터 선언 방법은
반환 값 (*함수포인터이름)(매개변수 타입); 으로 이루어진다.
예) void (*m_work_handler)(int inputData);
아래 예제를 보자. 함수 포인터를 만들고 정의하기 위해서 라이브러리 개발자가 고심한 것이 눈에 보인다. 함수 앞에 그냥 *만 사용하면 void *와 헷갈리기 때문에 어쩔 수 없이 () 괄호로 묶어야 했을 것이다. 이런 고충을 생각하면서 외우면 잘 기억난다. 함수 포인터도 함수기 때문에 꼭 매개변수 타입을 지정해 주어야 한다.
//함수 포인터 선언 void (*m_work_handler)(int inputData);2. 함수 포인터 사용 예
m_work_handler에 move_to_box함수를 집어넣고 m_work_handler를 실행하면 move_to_box 함수가 실행되는 것을 알 수 있다.
//함수 포인터 선언 void (*m_work_handler)(int inputData); //기본 함수 선언(함수 포인터 매개변수 리턴타입과 맞추어 선언합니다.) void move_to_box(int speed); void main() { //함수 포인터(m_work_handler)에 move_to_box 함수 집어 넣기 m_work_handler = move_to_box; m_work_handler(100); } void move_to_box(int speed) { //작업 내용 printf("상자를 %d 속도로 옮깁니다.",speed); } ==========out============ 상자를 100 속도로 옮깁니다.이를 좀 더 활용해 보자.
m_work_handler 함수 포인터에 함수만 바꾸어주면 동일한 함수 포인터로 다른 함수를 수행할 수 있다. 이 예제를 좀 더 활용하면 제사 용성을 높이는 코드를 개발할 수 있다.
//함수 포인터 선언 void (*m_work_handler)(int inputData); //기본 함수 선언(함수 포인터 매개변수 리턴타입과 맞추어 선언합니다.) void move_to_box(int speed); void main() { //함수 포인터(m_work_handler)에 move_to_box 함수 집어 넣기 m_work_handler = move_to_box; m_work_handler(100); m_work_handler = throw_away_the_box; m_work_handler(50); } void move_to_box(int speed) { //작업 내용 printf("상자를 %d 속도로 옮깁니다. \n",speed); } void throw_away_the_box(int speed) { //작업 내용 printf("상자를 %d 속도로 버립니다. \n",speed); } ==========out============ 상자를 100 속도로 옮깁니다. 상자를 50 속도로 버립니다.3. 함수 포인터 매개변수 및 반환 예
함수 포인터를 매개변수로 전달하거나 return 값으로 반환이 가능하다. 이를 C++ Class를 사용해서 설명해 본다
Robot class는 m_work_handler이라는 함수 포인터를 가지고 있고 이 함수 포인터를 set(설정)해주거나 get(반환)하는 함수를 가지고 있다.
class Robot { private: void (*m_work_handler)(int inputData); public: //함수 포인터 매개변수 사용 void set_work_handler(void (*inn_m_work_handler)(int inputData)) { m_work_handler = inn_m_work_handler; } //함수 포인터 리턴 사용 void (*get_work_handler())(int inputData) { return m_work_handler; } };3.1 매개변수로 사용될 때
매개변수로 사용될 때는 기존 함수 포인터를 선언했던 것 그대로 매개변수 위치에 입력해 주면 된다.
기본 함수 선언 방법:
리턴 타입 함수이름(매개변수)
함수포인터 매개변수 선언 방법:
리턴타입 함수이름(함수포인터_반환타입 (*매개변수로 사용할 함수포인터 이름)(함수포인터_매개변수))
3.2 리턴으로 사용될 때
이 경우가 조금 특이한데 기존 함수 포인터 이름 지정은 필요 없어지기 때문에 제거되고 반환 타입과 매개변수 타입만 남게 된다. 설명보다는 아래 '함수포인터 매개변수 선언 방법'을 보자.
함수포인터 매개변수 선언 방법:
함수포인터_반환타입 (*함수이름(매개변수))(함수포인터_매개변수)
예제를 통해 한번 따라 하고 외우거나 헷갈리면 선언 방법을 숙지해서 사용하는게 좋을 듯하다.
C언어의 함수에 관해서는 이전 포스팅에서 설명했다.
//ansan-survivor.tistory.com/1224
[C언어] C언어 함수 만들기, 함수 구조, 함수 템플릿, 함수 작동 순서
C언어 함수의 구조는 [return 타입] 함수명( [input타입 변수명] ) ex) int main( int a ) 함수명은 말 그대로 함수 이름 지정. input 은 이 함수가 실행되기 위한 입력 값을 지정하는것. return 타입은..
ansan-survivor.tistory.com
C언어 함수의 구조는 아래와 같다.
[return 타입] 함수명( [input타입 변수명] )
ex) int main( int a )
함수명은 말 그대로 함수 이름 지정.
input 은 이 함수가 실행되기 위한 입력 값을 지정하는것.
return 타입은 이 함수가 연산이되어 return되는 값의 타입.
즉 자세히 보면, 2가지의 Type이 선언되어야 한다.
1. input이 되는 값의 타입
2. return되는 인자의 타입
함수는 컴파일시 그 이름 자체로 메모리에 있는 특정 주소값으로 치환된다. 즉 함수 이름자체는 "상수형 포인터"이다.
즉, 함수의 이름 그자체는 실제로 메모리의 특정 주소값 (0x0000)를 가리키고 있는 포인터 이다.
다만 함수이름 포인터는 input인자의 type정보와, return인자의 type정보가 함께 제공되어야 한다. (void가 아니라면)
* 함수포인터를 선언하는 방법
1. 함수의 이름은 함수가 저장된 메모리공간을 가리키는 상수형 포인터이다. (함수 이름 자체는 상수형 타입으로
변경 불가)
2. 함수이름의 의미하는 '주소값' 은 "함수 포인터 변수"를 선언해 저장가능. (함수의 주소값을 가리키는 변수 선언 가능)
3. 함수포인터변수를 선언하려면, 사용할 함수의 반환, 매개변수 Type(자료형)을 알아야 한다.
아래 예제에서는 2개의 함수를 선언했다.
그리고
int (*fptr) (int, int); <= input parameter의 이름은 중요하지 않다. type만 넣으면 된다. (2개가 입력되므로 int, int)
void (*ptrstring) (char*);
두 함수포인터를 선언해서 사용.
#include <stdio.h> /* 포인터를 선언하기 위해서는, 주소값과 자료형이 주어져야 하는데, 함수의 이름을 다음과 같이 생각하고 포인터를 선언한다. 함수 읽기. (함수포인터를 선언하기 위하여) ex) int fct(int a ); 1. 이 함수의 주소값은? fct의 주소. (함수이름 = 주소값) 2. type형은? "Parameter가 int 이고, return값이 int 이다." ex) double Fct (double a , double b ); 1. 함수의 주소값? 함수이름 Fct 의 주소. 2. type형은? "Parameter가 2개의 double, return값이 double 이다." 아래 예제에서 선언한 함수포인터변수 2개. int (*fptr) (int, int); void (*ptrstring) (char *); */ int fct(int a, int b) { int c = 0; c = a - b; return c; } void ShowString(char* str) { printf("%s \n", str); } int main() { char* str = "ich liebe dich"; // 함수포인터를 선언하기!! // [자료형: 매개변수 int형인, 리턴값이 int형 2개인] 포인터함수 fptr 를 선언!! // 함수이름은 의미없다. *만 있으면 될뿐, 그러나 자료형은 반드시 일치해야 한다. int(*fptr) (int, int); fptr = fct; // fptr -> fct의 주소를 가리킴. (함수이름이 주소값이므로) // 상수 함수 포인터로 출력 printf("%d \n", (fct(5, 7))); // 변수 함수 포인터로 출력 printf("%d \n", (fptr(10, 15))); // 함수 포인터 선언하기. // 자료형: char * (케릭터 포인터형을 매개변수로 받고, return값은 없다) void(*ptrstring)(char*); // ptrstring -> ShowString함수를 가리킴. ptrstring = ShowString; ShowString(str); ptrstring(str); return 0; } /* fct 는 '상수' 함수포인터 이름이 될 수 있다! (변경 불가) fptr 은 '변수' 함수포인터 이름이 될 수 있다! (변경 가능) */(결과)
받는 인자 int, int 와 출력인자 int 타입인 *fptr 이름의 함수포인터를 선언.
fptr = fct
위 과정을 아래와 같이 도식화 하면,
함수 fct는 이미 특정 메모리주소에 '상수형포인터' 으로써 저장되고,
함수포인터가 선언되고 그 함수를 인자로 받게 되면, 이제 그 함수를 가리키게 된다.
함수포인터는 '변수형포인터' 으로 동일하게 사용한다.
문자열도 마찬가지로 함수포인터를 선언하면 동일하게 사용 가능하다.