함수 포인터의 요점은 무엇입니까?
함수 포인터의 유용성을 보는 데 문제가 있습니다. 어떤 경우에는 유용 할 수 있다고 생각하지만 (결국 존재하는 경우) 함수 포인터를 사용하는 것이 더 낫거나 피할 수없는 경우는 생각할 수 없습니다.
함수 포인터 (C 또는 C ++)를 잘 사용하는 몇 가지 예를 들어 주시겠습니까?
대부분의 예는 졸이다 콜백 : 당신은 함수를 호출 f()
하는 다른 함수의 주소를 전달 g()
하고, f()
호출 g()
일부 특정 작업에 대한합니다. 대신 f()
주소 를 전달 하면 h()
대신 f()
다시 전화 h()
합니다.
기본적으로 이것은 함수 를 매개 변수화 하는 방법 입니다. 동작의 일부는으로 하드 코딩되지 않고 f()
콜백 함수로 코딩됩니다 . 호출자는 f()
다른 콜백 함수를 전달 하여 다르게 행동 할 수 있습니다 . 클래식은 qsort()
C 표준 라이브러리에서 가져온 것으로, 정렬 기준을 비교 함수에 대한 포인터로 사용합니다.
C ++에서 이는 종종 함수 객체 (펑 터라 고도 함)를 사용하여 수행됩니다 . 이들은 함수 호출 연산자를 오버로드하는 객체이므로 마치 함수 인 것처럼 호출 할 수 있습니다. 예:
class functor {
public:
void operator()(int i) {std::cout << "the answer is: " << i << '\n';}
};
functor f;
f(42);
이 개념은 함수 포인터와 달리 함수 객체가 알고리즘뿐 아니라 데이터도 전달할 수 있다는 것입니다.
class functor {
public:
functor(const std::string& prompt) : prompt_(prompt) {}
void operator()(int i) {std::cout << prompt_ << i << '\n';}
private:
std::string prompt_;
};
functor f("the answer is: ");
f(42);
또 다른 장점은 함수 포인터를 통한 호출보다 함수 객체에 대한 호출을 인라인하는 것이 더 쉽다는 것입니다. 이것이 C ++에서 정렬하는 것이 때때로 C에서 정렬하는 것보다 빠른 이유입니다.
글쎄, 나는 일반적으로 점프 테이블 에서 (전문적으로) 사용합니다 ( 이 StackOverflow 질문 참조 ).
점프 테이블은 유한 상태 머신 에서 일반적으로 (배타적이지는 않음) 사용되어 데이터 기반을 만듭니다. 중첩 된 스위치 / 케이스 대신
switch (state)
case A:
switch (event):
case e1: ....
case e2: ....
case B:
switch (event):
case e3: ....
case e1: ....
2d 배열 또는 함수 포인터를 만들고 handleEvent[state][event]
예 :
- 맞춤 정렬 / 검색
- 다양한 패턴 (예 : 전략, 관찰자)
- 콜백
함수 포인터의 유용성에 대한 "고전적인"예 qsort()
는 빠른 정렬을 구현하는 C 라이브러리 함수입니다. 사용자가 생각 해낼 수있는 모든 데이터 구조에 대해 보편적이되기 위해서는 정렬 가능한 데이터에 대한 두 개의 void 포인터와 이러한 데이터 구조의 두 요소를 비교하는 방법을 알고있는 함수에 대한 포인터가 필요합니다. 이를 통해 작업에 대해 선택한 기능을 생성 할 수 있으며 실제로 런타임에 비교 기능 (예 : 오름차순 또는 내림차순 정렬)을 선택할 수도 있습니다.
나는 여기서 현재에 반대 할 것입니다.
C에서 함수 포인터는 사용자 정의를 구현하는 유일한 방법입니다. OO가 없기 때문입니다.
C ++에서는 동일한 결과에 대해 함수 포인터 또는 펑터 (함수 객체)를 사용할 수 있습니다.
The functors have a number of advantages over raw function pointers, due to their object nature, notably:
- They may present several overloads of the
operator()
- They can have state / reference to existing variables
- They can be built on the spot (
lambda
andbind
)
I personally prefer functors to function pointers (despite the boilerplate code), mostly because the syntax for function pointers can easily get hairy (from the Function Pointer Tutorial):
typedef float(*pt2Func)(float, float);
// defines a symbol pt2Func, pointer to a (float, float) -> float function
typedef int (TMyClass::*pt2Member)(float, char, char);
// defines a symbol pt2Member, pointer to a (float, char, char) -> int function
// belonging to the class TMyClass
The only time I have ever seen function pointers used where functors could not was in Boost.Spirit. They have utterly abused the syntax to pass an arbitrary number of parameters as a single template parameter.
typedef SpecialClass<float(float,float)> class_type;
But since variadic templates and lambdas are around the corner, I am not sure we will use function pointers in pure C++ code for long now.
In C, the classic use is the qsort function, where the fourth parameter is pointer to a function to use to perform the ordering within the sort. In C++, one would tend to use functors (objects that look like functions) for this kind of thing.
Agree with all of the above, plus.... When you load a dll dynamically at runtime you'll need function pointers to call the functions.
I used function pointers recently to create an abstraction layer.
I have a program written in pure C that runs on embedded systems. It supports multiple hardware variants. Depending on the hardware I am running on, it needs to call different versions of some functions.
At initialization time, the program figures out what hardware it is running on and populates the function pointers. All of the higher-level routines in the program just call the functions referenced by pointers. I can add support for new hardware variants without touching the higher-level routines.
I used to use switch/case statements to select the proper function versions, but this became impractical as the program grew to support more and more hardware variants. I had to add case statements all over the place.
I also tried intermediate function layers to figure out which function to use, but they didn't help much. I still had to update case statements in multiple places whenever we added a new variant. With the function pointers, I only have to change the initialization function.
Like Rich said above, it is very usual for functions pointers in Windows to reference some address that stores function.
When you programming in C language
on Windows platform you basically load some DLL file in primary memory(using LoadLibrary
) and to use the functions stored in DLL you need to create functions pointers and point to these address (using GetProcAddress
).
References:
Function pointers can be used in C to create an interface against which to program. Depending on the specific functionality that is needed at runtime, a different implementation can be assigned to the function pointer.
My main use of them has been CALLBACKS: when you need to save information about a function to call later.
Say you're writing Bomberman. 5 seconds after the person drops the bomb, it should explode (call the explode()
function).
Now there's 2 ways to do it. One way is by "probing" all bombs on the screen to see if they're ready to explode in the main loop.
foreach bomb in game
if bomb.boomtime()
bomb.explode()
Another way is to attach a callback to your clock system. When a bomb is planted, you add a callback to make it call bomb.explode() when the time is right.
// user placed a bomb
Bomb* bomb = new Bomb()
make callback( function=bomb.explode, time=5 seconds ) ;
// IN the main loop:
foreach callback in callbacks
if callback.timeToRun
callback.function()
Here callback.function()
can be any function, because it is a function pointer.
A different perspective, in addition to other good answers here:
In C, there are only function pointers, there aren't any functions.
I mean, you write functions, but you cant manipulate functions. There's no run-time representation of a function as such. You can't even call "a function". When you write:
my_function(my_arg);
what you're actually saying is "perform a call to the my_function
pointer with the specified argument". You're making a call via a function pointer. This decay to function pointer means that the following commands are equivalent to the previous function call:
(&my_function)(my_arg);
(*my_function)(my_arg);
(**my_function)(my_arg);
(&**my_function)(my_arg);
(***my_function)(my_arg);
and so on (thanks @LuuVinhPhuc).
So, you're already using function pointers as values. Obviously you would want to have variables for those values - and here is where all the uses other metion come in: Polymorphism/customization (like in qsort), callbacks, jump tables etc.
In C++ things are a bit more complicated, since we have lambdas, and objects with operator()
, and even an std::function
class, but the principle is still mostly the same.
For OO languages, to perform polymorphic calls behind the scenes (this is also valid for C up to some point I guess).
Moreover, they're very useful to inject different behaviour to another function (foo) at runtime. That makes function foo higher-order function. Besides it's flexibility, that makes the foo code more readable since it let's you pull that extra logic of "if-else" out of it.
It enables many other useful things in Python like generators, closures etc.
Use of function pointer
To call function dynamically based on user input. By creating a map of string and function pointer in this case.
#include<iostream>
#include<map>
using namespace std;
//typedef map<string, int (*)(int x, int y) > funMap;
#define funMap map<string, int (*)(int, int)>
funMap objFunMap;
int Add(int x, int y)
{
return x+y;
}
int Sub(int x, int y)
{
return x-y;
}
int Multi(int x, int y)
{
return x*y;
}
void initializeFunc()
{
objFunMap["Add"]=Add;
objFunMap["Sub"]=Sub;
objFunMap["Multi"]=Multi;
}
int main()
{
initializeFunc();
while(1)
{
string func;
cout<<"Enter your choice( 1. Add 2. Sub 3. Multi) : ";
int no, a, b;
cin>>no;
if(no==1)
func = "Add";
else if(no==2)
func = "Sub";
else if(no==3)
func = "Multi";
else
break;
cout<<"\nEnter 2 no :";
cin>>a>>b;
//function is called using function pointer based on user input
//If user input is 2, and a=10, b=3 then below line will expand as "objFuncMap["Sub"](10, 3)"
int ret = objFunMap[func](a, b);
cout<<ret<<endl;
}
return 0;
}
This way we have used function pointer in our actual company code. You may write 'n' number of function and call them using this method.
OUTPUT:
Enter your choice( 1. Add 2. Sub 3. Multi) : 1 Enter 2 no :2 4 6 Enter your choice( 1. Add 2. Sub 3. Multi) : 2 Enter 2 no : 10 3 7 Enter your choice( 1. Add 2. Sub 3. Multi) : 3 Enter 2 no : 3 6 18
I use function pointers extensively, for emulating microprocessors that have 1-byte opcodes. An array of 256 function pointers is the natural way to implement this.
One use of function pointer could be where we may not want to modify the code where the function is getting called (meaning thereby the call might be conditional and under different conditions, we need to do different sort of processing). Here the function pointers are very handy, since we do not need to modify the code at the the place where the function is getting called. We simply call the function using the function pointer with appropriate arguments. The function pointer can be made to point to different functions conditionally. (This can be done somewhere during initialization phase). Moreover the above model is very helpful, if we are not in position to modify the code where it is getting called (suppose it's a library API we can't modify). The API uses a function pointer for calling the appropriate user defined function.
참고URL : https://stackoverflow.com/questions/2592137/what-is-the-point-of-function-pointers
'program tip' 카테고리의 다른 글
Sublime Text 2 및 3 : 동일한 파일을 여러 번 열기 (0) | 2020.09.18 |
---|---|
저장 프로 시저 'dbo.aspnet_CheckSchemaVersion'을 찾을 수 없습니다. (0) | 2020.09.18 |
Python을 통한 Linux의 프로세스 목록 (0) | 2020.09.18 |
자바 스크립트 / 정규식 : 괄호 사이의 텍스트 제거 (0) | 2020.09.18 |
다른 bat 파일의 백그라운드에서 bat 파일을 어떻게 실행합니까? (0) | 2020.09.18 |