web-dev-qa-db-ja.com

Typedef関数ポインタ?

DLLを動的にロードする方法を学んでいますが、理解できないのはこの行です。

typedef void (*FunctionFunc)();

いくつかの質問を聞きたいんです。誰かがそれらに答えることができれば私は感謝するでしょう。

  1. なぜtypedefが使われているのですか?
  2. 構文は奇妙に見えます。 voidの後に関数名などはありませんか?無名関数のように見えます。
  3. 関数のメモリアドレスを格納するために関数ポインタが作成されていますか?

だから私は今混乱しています。あなたは私のために物事を明確にすることができますか?

402
Jack Harvin

typedefは、名前を型に関連付ける言語構成体です。
元の型と同じように使います。例えば、

  typedef int myinteger;
  typedef char *mystring;
  typedef void (*myfunc)();

好きに使う

  myinteger i;   // is equivalent to    int i;
  mystring s;    // is the same as      char *s;
  myfunc f;      // compile equally as  void (*f)();

ご覧のとおり、 typedefed という名前を上記の定義で置き換えることができます。

問題は、CおよびC++における関数の構文と読みやすさへのポインタにあり、typedefはそのような宣言の読みやすさを向上させることができます。ただし、他の単純な型とは異なり、関数は戻り値とパラメータを持つことがあるため、構文は適切です。したがって、関数へのポインタの宣言が長く複雑になることがあります。

読みやすさは、関数配列へのポインタ、そして他のいくつかのより間接的なフレーバーを使って本当にトリッキーになり始めるかもしれません。

3つの質問に答える

  • なぜtypedefが使われるの? コードの読みやすさ - 特に関数へのポインタ、または構造体の名前のために。

  • 構文は奇妙に見えます(関数宣言へのポインタの中で) その構文は、少なくとも始めては読むことが明らかではありません。代わりにtypedef宣言を使用すると読みやすくなります

  • 関数のメモリアドレスを格納するための関数ポインタが作成されていますか。 はい、関数ポインタは関数のアドレスを格納します。これは、プログラムの書き込み/読み取りを容易にするだけのtypedef構文とは関係ありません。コンパイラは実際のコードをコンパイルする前にtypedef定義を展開するだけです。

例:

typedef int (*t_somefunc)(int,int);

int product(int u, int v) {
  return u*v;
}

t_somefunc afunc = &product;
...
int x2 = (*afunc)(123, 456); // call product() to calculate 123*456
417
Ring Ø
  1. typedefは型のエイリアスに使われます。この場合、FunctionFuncvoid(*)()にエイリアスしています。

  2. 確かに、構文は奇妙に見えます、これを見てください:

    typedef   void      (*FunctionFunc)  ( );
    //         ^                ^         ^
    //     return type      type name  arguments
    
  3. いいえ、これは単にFunctionFunc型が関数ポインタになることをコンパイラに伝えるだけで、 define oneのようにはなりません。

    FunctionFunc x;
    void doSomething() { printf("Hello there\n"); }
    x = &doSomething;
    
    x(); //prints "Hello there"
    
173
Jacob Relkin

typedef Wordがないと、C++では、宣言は引数なしの関数へのポインタ型の変数FunctionFuncを宣言し、voidを返します。

typedefを使うと、代わりにFunctionFuncをその型の名前として定義します。

29

C++ 11を使用できる場合は、std::functionおよびusingキーワードを使用することをお勧めします。

using FunctionFunc = std::function<void(int arg1, std::string arg2)>;
7
#include <stdio.h>
#include <math.h>

/*
To define a new type name with typedef, follow these steps:
1. Write the statement as if a variable of the desired type were being declared.
2. Where the name of the declared variable would normally appear, substitute the new type name.
3. In front of everything, place the keyword typedef.
*/

// typedef a primitive data type
typedef double distance;

// typedef struct 
typedef struct{
    int x;
    int y;
} point;

//typedef an array 
typedef point points[100]; 

points ps = {0}; // ps is an array of 100 point 

// typedef a function
typedef distance (*distanceFun_p)(point,point) ; // TYPE_DEF distanceFun_p TO BE int (*distanceFun_p)(point,point)

// prototype a function     
distance findDistance(point, point);

int main(int argc, char const *argv[])
{
    // delcare a function pointer 
    distanceFun_p func_p;

    // initialize the function pointer with a function address
    func_p = findDistance;

    // initialize two point variables 
    point p1 = {0,0} , p2 = {1,1};

    // call the function through the pointer
    distance d = func_p(p1,p2);

    printf("the distance is %f\n", d );

    return 0;
}

distance findDistance(point p1, point p2)
{
distance xdiff =  p1.x - p2.x;
distance ydiff =  p1.y - p2.y;

return sqrt( (xdiff * xdiff) + (ydiff * ydiff) );
}
1
Amjad

一般的な構文の場合は、ANSI C規格の 附属書A を参照してください。

そこからのBackus-Naur形式では、typedefの型がstorage-class-specifierであることがわかります。

declaration-specifiers型では、多くの指定子型を混在させることができることがわかりますが、その順序は関係ありません。

例えば、

long typedef long a;

along longの別名として定義します。そのため、徹底的な使用法についてtypedefを理解するには、構文を定義するバッカスナウア形式を調べる必要があります(ISOだけでなく、ANSI Cにも正しい文法が多数あります)。

Typedefを使用して関数型の別名を定義するときは、関数の識別子を配置する場所と同じ場所に別名を配置する必要があります。あなたの場合は、呼び出し時に型チェックが無効になり、何も返さない関数のエイリアスとして型FunctionFuncを定義します。

0
alinsoar