C 관련 포스팅 목록
2021.12.19 - [C/stdio] - C 파일 오프셋 위치 이동 예제 - 2(stdio/fseek/SEEK_END)
2021.12.18 - [C/stdio] - C 파일 오프셋 위치 이동 예제 - 1(stdio/fseek/SEEK_SET)
2021.12.05 - [C/stdio] - C 파일 실시간 쓰기 예제(stdio/fflush)
2021.12.01 - [C/stdio] - C 파일 생성 및 스트림 열기 예제(stdio/fopen)
2021.11.30 - [C/stdio] - C 파일 스트림 닫기 예제(stdio/fclose)
C에서 함수 포인터 변수를 사용하여 함수 호출하기
안녕하세요.
오늘은 C/C++ 에서 함수 포인터 변수를 활용한 예제들을 알아보도록 하겠습니다. 포인터 변수라고하면 정말 지긋지긋 벌써부터 머리가 아파오는데... 우리가 처음 C언어 방법론 등을 공부할 때 반드시 나오는 산이 있습니다. 바로 함수 포인터입니다.
아니... 포인터도 어려워 이해 못 하는데 함수 포인터는 또 뭐야? 라고 생각을 하게 되죠. 저도 물론 그랬습니다. 오늘 포스팅을 이해하기 위해선 포인터에 대한 이해가 반드시 중요하기도 합니다. 포인터에 대한 상세한 설명은 다음 포스팅에서 다루도록 하고 오늘은 최대한 함수 포인터의 사용 예제를 눈에 익히고 친해지는 계기가 되는 그러한 포스팅을 쓰도록 하겠습니다.
포인터에 대해 간략하고 쉽게 설명하고 넘어가자면 포인터는 주소를 저장하는 변수입니다. 그리고 주소를 가리키는 역할도 합니다. 우리가 코딩을 하면서 수많은 변수, 함수, 상수, 라이브러리 등을 사용합니다. 이 모든 것들은 제 각각 컴파일이라는 실행 프로그램으로 만들어지는 과정을 거치면서 자신의 주소를 가집니다.
이게 무슨 말이냐면 코드가 컴파일되어 실행 프로그램이 만들어지면 이 프로그램이 실행되는 과정에서 이전 코드에서 사용한 변수, 함수 들을 똑같이 불러야 합니다. 불러야 그 기능들이 실행되겠죠?
근대 그 기능들이 도대체 어디 존재하는가가 문제가 됩니다.다시 말하자면, 컴퓨터의 주기억장치라는 공간 속에 그 코드들이 도대체 어디에 있을까? 입니다.자, 이 내용은 정말 중요합니다.
우리가 택배를 시켜도 택배 물품이 우리 집까지 정상적으로 오려면 택배 기사님이 우리 집의 주소를 알아야 올 수 있습니다. 주소도 모르는데 택배 물품이 올 수가 없죠.
마찬가지로 컴퓨터가 어떠한 기능을 실행할 때도 그 기능의 위치를 알아야 실행이 가능합니다. 그래서 C 언어의 포인터는 이러한 기억 공간 속의 위치를 가리키는 주소를 관리할 수 있는 변수입니다.
개발자가 마음대로 특정 주소의 있는 값을 가져오거나 아니면 특정 주소를 저장하거나 그러한 일들을 하는 것이지요. 그렇다면 함수 포인터는 말 그대로 특정 함수들의 위치를 저장하거나 가리킨다는 의미입니다.
자 그러면 함수 포인터를 활용한 간단한 예제를 통해 알아보도록 하겠습니다.
함수 포인터 변수 선언 및 호출하기
#include <stdio.h>
#include <string.h>
void print_text() {
printf("hello world!\n");
}
int main()
{
void (*func)();
func = print_text;
func();
}
라인 설명
4-6: "hello world!" 라는 문자열을 출력하는 함수인 "print_text" 를 구현합니다. 이 함수는 반환이 없는 void 형이고 인자도 없습니다.
10: 일반적인 함수 포인터 변수 선언 방법입니다. 우리는 본 예제에서 func라는 이름을 가진 함수 포인터 변수를 만들고 그 변수에 "print_text" 함수의 주소를 저장하여 func 변수를 함수처럼 호출해도 실제로는 print_text 함수가 호출되도록 할 것입니다. "void (*func)();" 구문은 아래와 같은 의미가 있습니다.
void: "print_text" 함수의 반환형이 void 이기 때문에 void로 선언(*func): 함수 포인터 변수 이름입니다. 포인터 변수이기 때문에 앞에 *가 붙습니다. 본 예제에서는 함수 포인터의 이름을 func로 하였습니다.(): "print_text" 함수는 인자가 없기 때문에 func 함수 포인터 변수 선언 시 인자도 ()로 설정합니다.
11: 위에서 만든 함수 포인터 변수인 func에 똑같은 함수 구조인 "print_text" 함수명을 저장합니다. C에서 함수명을 포인터 변수에 대입하면 기억장치에서 존재하는 해당 함수의 주소 값이 저장됩니다.13: 일반적인 함수 호출 방법처럼 func() 구문을 호출합니다. 그러면 아래와 같이 func에 저장된 "print_text" 함수의 주소로 찾아가 print_text 함수를 실행합니다.
인자가 있는 함수 포인터 변수 선언 및 호출 예제
#include <stdio.h>
#include <string.h>
void print_name(const char *name) {
printf("my name is %s\n", name);
}
int main()
{
void (*func)(const char *);
func = print_name;
func("hongmimi");
}
라인 설명
4-6: 이전의 "print_text" 함수와 달리 이름 문자열을 인자로 전달받아 출력하는 "print_name" 함수를 선언합니다.
10: func 함수 포인터 선언 시 "print_name" 함수의 반환형인 void, 그리고 선언하려는 함수 포인터 변수이름과 이전과 달리 인자가 생겼기 때문에 같은 인자형인 (const char *)를 입력합니다.
13: 기존처럼 func 함수 포인터 변수를 호출하지만 인자도 같이 전달합니다. 그러면 아래와 같이 정상적으로 이름이 출력됩니다.
함수 포인터 선언시 인자의 변수명 입력은 개발자의 선택이다.
void (*func)(const char *name);
func = print_name;
func("hongmimi");
라인 설명
1: 함수 포인터의 인자 선언시 변수명을 입력한다면 다른 개발자가 해당 코드를 볼 때 가독성이 편해지지만 또 한편으론 함수 포인터 변수를 사용하는 이유는 가리키는 함수가 자주 바뀔 때 보통 사용하기 때문입니다. 따라서 인자 변수명이 매번 똑같을 수는 없기 때문에 보통 사용하지 않습니다.
마무리
오늘은 함수 포인터의 기본적인 선언 및 호출 방법에 대해 알아보았습니다. 다음 예제에서는 구조체 멤버 변수로 함수 포인터를 설정하여 호출하는 방법과 실제 어떤 환경에서 함수 포인터를 자주 사용하는지 알아보도록 하겠습니다.
C 관련 포스팅 목록
2021.12.19 - [C/stdio] - C 파일 오프셋 위치 이동 예제 - 2(stdio/fseek/SEEK_END)
2021.12.18 - [C/stdio] - C 파일 오프셋 위치 이동 예제 - 1(stdio/fseek/SEEK_SET)
2021.12.05 - [C/stdio] - C 파일 실시간 쓰기 예제(stdio/fflush)