2

私はJavaのバックグラウンドから、Cを初めて使用します。

構造体定義内の関数からのデータを使用してその場で初期化される構造体がある場合、それらの関数はいつ呼び出されますか?このコードはいつ実行されますか?それはちょうど最初の参照にありsample_struct_table[i]ますか?

static struct sample_struct {
    int         command;
    int         (*foo)( obj1 *banana, int num);
} sample_struct_table[] = {
    {   .command    =   COMMAND_1,
        .foo =   function_name,
    },
    {   .command    =   COMMAND_2,
        .foo =   another_function_name,
    },
};

static int function_name(obj1 *banana, int num)
{
      // do stuff here
      // When does this get called?
}
4

3 に答える 3

6

関数を呼び出すと、関数が呼び出されます。あなたの例では、あなたがしているのは、構造体のフィールドを関数ポインタに設定することだけです。関数は呼び出されず、それを指すポインターがあります。

于 2012-12-10T23:31:29.657 に答える
3

簡単な答え:配列内のポインターが呼び出されたときに呼び出されます。例えば:

sample_struct_table[0].foo(...);

(明らかに、楕円を関数の呼び出しに必要なパラメーターに置き換えます)。

長い答え:Cは関数へのポインターを持つことができます。つまり、共有オブジェクト(.dll、.soなど)をロードし、実行時に定義された関数を探し、それらにリンクせずにそれらの関数を呼び出すことができます。これは非常に強力です。関数へのポインターを含む構造体を作成している場合、これは、ループを使用して一連の関数を呼び出したい場合にのみ非常に役立ちます。構造体の一部がintの場合、関数は次に呼び出す関数を指定できると思いますが、これが役立つシナリオは想像できません。Scalaに精通していて、システムで使用したことがある場合は、Scalaが常にこれを行っているため、これを理解するのは難しいことではありません。

scala> 1 to 10 foreach println

ここで、foreach関数は、単一のIntをパラメーターとして受け入れる関数を受け入れます。foreachのパラメーターとしてprintln関数(def println(x:Any)= ...)を渡します。

于 2012-12-10T23:47:38.137 に答える
2

予期しない62、あなたの混乱はの定義から生じていると思いますstruct。おそらくそれfooはタイプだと思いますか?int

我々は持っています:

static struct sample_struct {
    int         command;
    int         (*foo)( obj1 *banana, int num);
} sample_struct_table[] = {
    {   .command    =   COMMAND_1,
        .foo =   function_name,
    },
    {   .command    =   COMMAND_2,
        .foo =   another_function_name,
    },
};

sを使用してこれを少し書き直すことができtypedefます。最初の一歩:

typedef struct _sample_t
{
    int         command;
    int         (*foo)( obj1 *banana, int num);
} sample_t;

そしてそこから、2番目:

typedef int (*foo_t)( obj1 *banana, int num);
typedef struct _sample_t
{
    int         command;
    foo_t       foo;
} sample_t;

fooこれにより、Cを初めて使用する場合は、タイプが何であるかがより明確になります。

これで、配列の宣言と初期化を行っても、2つの関数のアドレスに加えて、それぞれの背後にあるリテラルに配列が初期化されます。COMMAND_1COMMAND_2

forここで、次のプログラム(値を即興で作成)があると仮定すると、関数の本体のループ内で関数を呼び出す方法を確認できますmain()

#include <stdio.h>
#include <stdlib.h>

#define COMMAND_1 1
#define COMMAND_2 2
typedef void* obj1;
static int function_name(obj1 *banana, int num);
static int another_function_name(obj1 *banana, int num);

typedef int (*foo_t)( obj1 *banana, int num);
typedef struct _sample_t
{
    int         command;
    foo_t       foo;
} sample_t;

sample_t sample_struct_table[] = {
    {   .command    =   COMMAND_1,
        .foo =   function_name,
    },
    {   .command    =   COMMAND_2,
        .foo =   another_function_name,
    },
};

static int function_name(obj1 *banana, int num)
{
    // do stuff here
    // When does this get called?
    return 0;
}

static int another_function_name(obj1 *banana, int num)
{
    // do stuff here
    // When does this get called?
    return 0;
}

int main(int argc, char** argv)
{
    int i;
    for(i = 0; i < sizeof(sample_struct_table)/sizeof(sample_struct_table[0]); i++)
    {
        printf("%i\n", i);
        if(sample_struct_table[i].foo(NULL, i))
            return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
}

TL; DR:

Pascalとは異なり、関数を呼び出すには常に言う必要がありますがfunction_name(...)function_name単にその関数のアドレスを参照するだけです。

于 2012-12-10T23:50:56.970 に答える