一連のデータに対してパラメーターによって渡される関数を実行する関数を作成したいと思います。Cで関数をパラメーターとしてどのように渡しますか?
void funcA(void(*funcB)(int))
とvoid (*funcA())()
するtypedef void funcB(); void funcA(funcB)
とfuncB funcA()
?上向きに見えない。
一連のデータに対してパラメーターによって渡される関数を実行する関数を作成したいと思います。Cで関数をパラメーターとしてどのように渡しますか?
void funcA(void(*funcB)(int))
とvoid (*funcA())()
するtypedef void funcB(); void funcA(funcB)
とfuncB funcA()
?上向きに見えない。
回答:
宣言
関数パラメーターを受け取る関数のプロトタイプは次のようになります。
void func ( void (*f)(int) );
これは、パラメータf
がvoid
戻り値の型を持ち、単一のint
パラメータを取る関数へのポインタになることを示しています。次の関数(print
)func
は、適切なタイプであるためパラメーターとして渡すことができる関数の例です。
void print ( int x ) {
printf("%d\n", x);
}
関数呼び出し
関数パラメーターで関数を呼び出す場合、渡される値は関数へのポインターでなければなりません。これには、関数名(括弧なし)を使用します。
func(print);
はを呼び出してfunc
、それにprint関数を渡します。
関数本体
他のパラメーターと同様func
に、関数の本体でパラメーターの名前を使用して、パラメーターの値にアクセスできるようになりました。レッツ言うfunc
それは数字0-4に渡される関数を適用します。最初に、printを直接呼び出す場合のループは次のようになります。
for ( int ctr = 0 ; ctr < 5 ; ctr++ ) {
print(ctr);
}
以来func
のパラメータ宣言は、それが言いf
たい関数へのポインタの名前で、我々は、場合ことを最初に思い出すf
のポインタで、その後*f
の事であるf
(つまり、関数にポイントprint
この場合)。その結果、上記のループ内のすべてのprintを次のように置き換えます*f
。
void func ( void (*f)(int) ) {
for ( int ctr = 0 ; ctr < 5 ; ctr++ ) {
(*f)(ctr);
}
}
f
関数呼び出しはどちらも、f
*なしでそのまま使用できます。ただし、パラメーターfが関数ポインターであることを明確にするために、これを同じように実行することをお勧めします。ただし、読みやすさが損なわれることがよくあります。
typedef
、関数ポインタの使用への単一の参照を行いませんか?申し訳ありませんが、反対票を投じる必要があります。
この質問にはすでに関数ポインタを定義するための答えがありますが、特にアプリケーションの周りでそれらを渡す場合は、非常に面倒になる可能性があります。この不快さを回避するために、関数ポインターをより読みやすいものにtypedefすることをお勧めします。例えば。
typedef void (*functiontype)();
voidを返し、引数を取らない関数を宣言します。この型への関数ポインターを作成するには、次のようにします。
void dosomething() { }
functiontype func = &dosomething;
func();
intを返し、charを取る関数の場合
typedef int (*functiontype2)(char);
そしてそれを使う
int dosomethingwithchar(char a) { return 1; }
functiontype2 func2 = &dosomethingwithchar
int result = func2('a');
関数ポインタを読みやすい型に変換するのに役立つライブラリがあります。ブースト機能のライブラリは素晴らしいですし、努力の価値があります!
boost::function<int (char a)> functiontype2;
上記よりもはるかに優れています。
typedef
です。それはより簡単で、追加のライブラリを必要としません。
C ++ 11以降では、関数ライブラリを使用して、これを簡潔かつ一般的な方法で行うことができます。構文は、例えば、
std::function<bool (int)>
ここでbool
は、最初の引数がtypeである1つの引数を持つ関数の戻り型ですint
。
以下にサンプルプログラムを含めました:
// g++ test.cpp --std=c++11
#include <functional>
double Combiner(double a, double b, std::function<double (double,double)> func){
return func(a,b);
}
double Add(double a, double b){
return a+b;
}
double Mult(double a, double b){
return a*b;
}
int main(){
Combiner(12,13,Add);
Combiner(12,13,Mult);
}
ただし、テンプレート関数を使用する方が便利な場合もあります。
// g++ test.cpp --std=c++11
template<class T>
double Combiner(double a, double b, T func){
return func(a,b);
}
double Add(double a, double b){
return a+b;
}
double Mult(double a, double b){
return a*b;
}
int main(){
Combiner(12,13,Add);
Combiner(12,13,Mult);
}
以下に示すように、関数のアドレスをパラメーターとして別の関数に渡します
#include <stdio.h>
void print();
void execute(void());
int main()
{
execute(print); // sends address of print
return 0;
}
void print()
{
printf("Hello!");
}
void execute(void f()) // receive address of print
{
f();
}
また、関数ポインタを使用して関数をパラメータとして渡すことができます
#include <stdio.h>
void print();
void execute(void (*f)());
int main()
{
execute(&print); // sends address of print
return 0;
}
void print()
{
printf("Hello!");
}
void execute(void (*f)()) // receive address of print
{
f();
}
ISO C11 6.7.6.3p8に従って、関数を関数ポインターとして「渡す」ことができます:「パラメーターを「関数の戻り値の型」として宣言すると、 6.3のように、「関数の戻り値の型へのポインター」に調整されます。 .2.1。 " たとえば、これ:
void foo(int bar(int, int));
これと同等です:
void foo(int (*bar)(int, int));
実際には関数ではありませんが、ローカライズされたコードです。もちろん、結果だけをコードに渡すわけではありません。後で実行するためにイベントディスパッチャーに渡された場合は機能しません(イベントが発生したときではなく、結果がすぐに計算されるため)。しかし、それがあなたがやろうとしているすべてのことなら、それはあなたのコードを1つの場所にローカライズします。
#include <stdio.h>
int IncMultInt(int a, int b)
{
a++;
return a * b;
}
int main(int argc, char *argv[])
{
int a = 5;
int b = 7;
printf("%d * %d = %d\n", a, b, IncMultInt(a, b));
b = 9;
// Create some local code with it's own local variable
printf("%d * %d = %d\n", a, b, ( { int _a = a+1; _a * b; } ) );
return 0;
}
IncMultInt
ますか?
typedef
。