C言語:関数のポインタ/コールバック関数
既存のポインタとは、データセグメントまたはスタックセグメントの変数のアドレスまたはメモリアドレスを格納するために使用されるデータポインタです.
このセクションでは、コード・セグメント内の文のアドレスを格納し、ポインタとして使用する方法について説明します.
関数ポインタ
int sum(int a, int b)
{
int result = 0;
result = a + b;
return result;
}
int result = sum(2,3);
int sum(int a, int b); == int(*p)(int, int); //*p로 sum함수를 호출한다.
p = ∑ //sum의 함수의 주소를 p에 저장한다.
なぜ関数のポインタを使用しますか?->同じ形式の関数をグループ化できるからです.
同じフォーマットは(パラメータ、資料型、同じ形式の戻り値)です.
次の例です.
<덧셈>
int sum(int a, int b)
{
return a+b;
}
<뺄셈>
int sub(int a, int b)
{
return a-b;
}
<곱셈>
int Mul(int a, int b)
{
return a * b;
}
<나눗셈>
int Div(int a, int b)
{
return a/b;
}
==============================
int result 1, result2, result3,result4;
result1 = sum(8,2);
result2 = sub(8,2);
result3 = Mul(8,2);
result4 = Div(8,2);
이 4개의 함수를 포인터 하나로 묶을 수 있다.
int (*p[4])(int , int) = {&sum, &sub, &Mul, &Div};
여기서 *p([4]) 와 (*p)[4]의 차이를 모른다면 포인터 부분을 다시 공부하도록 하자.
==========================================================
int (*p[4])(int int) = {&sum, &sub, &Mul, &Div};
int result[4], i; // 함수를 호출 했을 때 반환되는 값 4개를 저장할 배열을 선언
for(i = 0; i < 4; i++) result[i] = (*p[i])(8,2);
<関数ポインタを使用して繰り返し文で呼び出す>
#include <stdio.h>
int sum(int a, int b)
{
return a + b;
}
int sub(int a, int b)
{
return a - b;
}
int Mul(int a, int b)
{
return a * b;
}
int Div(int a, int b)
{
return a / b;
}
void main()
{
int (*p[4])(int ,int) = { &sum, &sub, &Mul, &Div };
char table[4] = { '+', '-', '*', '/' };
for (int i = 0; i < 4; i++)
{
printf("%d %c %d = %d\n", 8, table[i], 2, (*p[i])(8, 2));
}
}
<結果>
コールバック関数
-라이브러리 프로그래머가 만든 헤더 파일과 라이브러리 파일
<sum함수의 원형>
sum.h
1. int sum(int a, int b);
<두 값을 합산하는 함수>
sum.lib
int sum(int a, int b)
{
return a + b;
}
-라이브러리 사용자가 사용하는 형태
#include "sum.h"
#pragma commnet(lib, "sum.lib")
void main()
{
int result = sum(2,3);
}
※pragmaプリプロセッサを使用すると、コンパイラの各種設定値を変更できます.上で使用したフォーマットはsumです.これは、libファイルがプログラムで使用されることを意味します.
プログラマが2つの数値を負に変換するように要求した場合、プラスに変換する関数を追加します.sumbsという新しい関数を追加する必要があります.
-라이브러리 프로그래머가 만든 헤더 파일과 라이브러리 파일
<sum함수의 원형>
sum.h
1. int sum(int a, int b)
2. int sumabs(int a, int b)
sum.lib
int sum(int a, int b)
{
return a + b;
}
int sumabs(int a, int b)
{
if(a<0) a = a * (-1);
if(b<0) b = b * (-1);
return a + b;
}
-라이브러리 사용자가 사용하는 형태
#include "sum.h"
pragma commnet(lib, "sum.lib")
void main()
{
int result1, result2;
result1 = sum(2,-3);
result2 = sumabs(2, -3);
}
ライブラリに含まれる関数は、既存の機能を維持し、ユーザーが必要とするときに関数を変更する機能を提供することが望ましい.
ただし、プログラマはライブラリソースコード全体を提供できません.では、ライブラリユーザーはどのようにしてソースコードなしでライブラリを変更し、使用しますか?
関数をパラメータとして関数ポインタを使用すればよい.
void myabsolute(int *p)
{
if(*p<0) *p = (*p) * (-1);
}
int sumabs(int a, int b)
{
myabsolute(&a); // if (a<0) a = a * (-1)
myabsolute(&b); // if (b<0) b = b * (-1)
return a + b;
}
void (*p)(int *); 함수의 주소를 받아서 사용할 수 있다.
================================================
int sumabs(int a, int b, void (*fp_abs)(int*))
{
(*fp_abs)(&a);
(*fp_abs)(&b);
return a + b;
}
=================================================
sumabs(5,-1, &absolute); //sumabs함수에서 myabsolute 함수를 호출한 것과 같음
sum(5, -1, NULL); //sumabs 함수에서 myabsolute 함수를 사용하지 않는 경우
==================================================
<NULL에 대한 예외처리>
int sumabs(int a, int b, void (*fp_abs)(int *))
{
if(fp_abs != NULL) (*fp_abs)(&a);
if(fp_abs != NULL) (*fp_abs)(&b);
return a + b;
}
関数ポインタを使用して、異なるa、b変数に設定して使用します.-라이브러리 프로그래머 시점
<함수 원형>
-sum.h-
1. int sum(int a, int b. void(*pa)(int *), void(*pb)(int *))
-sum.lib-
int sum(int a, int b, void (*pa)(int *), void (*pb)(int *))
{
if(NULL != pa) (*pa)(&a);
if(NULL != pb) (*pb)(&b);
return a + b;
}
=============================================================
#include "sum.h"
#pragma comment(lib, "sum.lib")
void main()
{
int result = sum(-3, -2, NULL, NULL);
}
#include "sum.h"
pragma commnet(lib, "sum.lib")
void myabsolute(int* p)
{
if (*p < 0) *p = (*p) * (-1);
}
void main()
{
int result = sum(-3, -2, myabsolute, NULL);
}
==============================================================
-라이브러리 프로그래머 시점
<함수 원형>
-sum.h-
1. int sum(int a, int b. void(*pa)(int *), void(*pb)(int *))
===============================================================
-sum.lib-
int sum(int a, int b, void (*pa)(int *), void (*pb)(int *))
{
if(NULL != pa) (*pa)(&a);
if(NULL != pb) (*pb)(&b);
return a + b;
}
==============================================================
※호출관계를 파악해보자.
sum(-3,-2,myabsolute, NULL) <==>
int sum(int a, int b, void(*pa)(int *), void (*pb)(int *))
1. sum 함수의 pa변수가 NULL이 아니기 때문에 if(NULL != pa)(*pa)(&a); 문장이 수행된다.
2. sum의 pa 변수 == myabsolute // (*pa)(&a) == myabsolute(&a)
3. sum 함수의 매개변수 a의 주소 값이 myabsolute 함수의 포인터 변수 p에 저장된다.
4. myabsolute 포인터 변수인 p는 변수 a의 주소 값을 저장하고 있다.
5. 따라서 p가 가리키는 값은 음수인 -3이라서 if(*p<0) *p = (*p) * (-1); 조건문이 실행된다.
6. 함수의 포인터 pb는 NULL 값이 저장되어 있기 때문에 if(NULL!=pb) (*pb)(&b); 조건문은 실행 x
7. sum함수의 변수 a값이 -3에서 3으로 변경되었기 때문에 3 + (-2) 가 수행 -> 1이 반환
Reference
この問題について(C言語:関数のポインタ/コールバック関数), 我々は、より多くの情報をここで見つけました https://velog.io/@qlwb7187/C언어-함수의-포인터-콜백함수テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol