Programming/C

C언어 - 함수 포인터와 void 포인터

JunsuKim 2021. 10. 5.
728x90

메모리 공간에 저장되는 것은 변수뿐만이 아니라, 프로그램 실행의 흐름을 구성하는 함수들도 바이너리(binary) 형태로 저장된다. 그리고 메모리 공간에 저장된 함수의 주소 값을 저장하는 포인터 변수를 "함수 포인터 변수"라고 한다.

함수 포인터

함수 포인터의 포인터 형(타입)

프로그래밍을 할 때 정의되는 모든 함수는 프로그램 실행 시 메인 메모리에 저장되어 실행된다.

배열의 이름이 배열의 시작 주소 값을 의미하듯이, 함수의 이름은 함수가 저장된 메모리 공간의 주소 값을 의미한다.

함수 포인터 변수를 선언할 때는 먼저 함수 포인터의 포인터 형을 결정해야 한다.

변수에서도 그랬듯이 형을 결정하지 못하면 적절한 함수 포인터 변수의 선언이 불가능하다.

int SimpleFunc(int num) {
    . . . .
}

이 함수의 반환형은 int형이고, 매개변수는 int num이 선언되어 있다. 그리고 함수 이름인 SimpleFunc는 함수의 주소 값을 의미하는 상수 형태의 함수 포인터가 된다. 그렇다면 SimpleFunc의 타입은 무엇일까?

함수 포인터의 타입은 반환형과 매개변수의 선언을 통해 결정짓는다.

그러므로 SimpleFunc의 타입은 "반환형이 int이고, 매개변수로 int형 변수가 하나 선언된 포인터 형(타입)"이다.

결론적으로는 반환형과 매개변수의 선언 형태를 말하면 되는 것이다.

double SimpleFunc(doublee num1, double num2) {
    . . . .
}

 이 함수 이름의 타입은 반환형이 double이고, 매개변수 double형 변수가 두 개 선언된 포인터 형(타입)이 되는 것이다.

적절한 함수 포인터 변수의 선언

위에서 함수 포인터의 형을 결정하는 방법을 보았다. 이제 함수의 주소 값을 저장할 수 있는 포인터 변수를 선언하는 방법을 보자.

포인터 변수에는 반환형 정보와 매개변수 선언의 정보가 모두 표현되어 있어야 한다.

함수 포인터 변수를 선언하는 방법은 다음과 같다.

int (*ptr) (int);

/*
int -> 반환형이 int인 함수 포인터
(*ptr) -> ptr은 포인터
(int) -> 매개변수 선언이 int 하나인 함수 포인터
*/

이제 함수를 보며 포인터 변수를 어떻게 선언해야 할지 생각해보자.

int SimpleFunc(int n1, int n2) {
    . . . .
}

반환형이 int이고 매개변수로 int형 변수가 두 개 선언돼있는 SimpleFunc이다.

포인터 변수가 어떻게 선언될지를 생각해보자.

int (*ptr) (int, int);

int형으로 반환을 받으므로 반환형이 int인 함수 포인터가 선언되고, 매개변수가 int형이 두 개이므로  (int, int)를 사용하는 것이다.

이러한 함수 포인터 변수에 함수의 주소 값을 저장하기 위해선 대입 연산을 하면 된다.

ptr = SimpleFunc;

이렇게 연산을 하고 나면 ptr을 이용해서 SimpleFunc함수를 호출할 수 있게 된다.

ptr(3, 4);

SimpleFunc(3, 4)와 동일한 결과를 내게 된다.

void 포인터

void는 형(타입)이 존재하지 않는다. 이와 같은 void형 포인터 변수는 무엇이든지 담을 수 있다. 예를 들어

변수의 주소 값뿐만 아니라, 함수의 주소 값도 담을 수 있다.

선언 방식은 다음과 같다.

void *ptr;

void형 포인터 변수는 무엇이든 담을 수 있다는 장점이 있으나, 단점도 존재한다.

아무런 포인터 연산을 하지 못하는 것이다. 또한 값의 변경, 참조도 불가능하다. void형 포인터 변수에는 가리키는 대상에 대한 형(타입)의 정보가 담겨있지 않기 때문이다.

void형 포인터는 "일단 주소 값에만 의미를 두고, 포인터 형을 나중에 결정한다"의 경우에 사용하면 좋다.

 

728x90

댓글