web-dev-qa-db-ja.com

Cで関数の配列を定義する方法

次のような宣言を含む構造体があります。

void (*functions[256])(void) //Array of 256 functions without arguments and return value

そして別の関数でそれを定義したいのですが、256の関数があります!私はこのようなことをすることができます:

struct.functions[0] = function0;
struct.functions[1] = function1;
struct.functions[2] = function2;

などなどですが、これは面倒です。私の質問は、このようなことを行う方法はありますか?

struct.functions = { function0, function1, function2, function3, ..., };

[〜#〜] edit [〜#〜]:ChrisLutzが言ったように構文エラーが修正されました。

17
0x77D

次のような宣言を含む構造体があります。

いいえ、しません。これは構文エラーです。あなたが探しています:

_void (*functions[256])();
_

これは関数ポインタの配列です。ただし、void func()は「引数を取らず何も返さない関数」ではないことに注意してください。これは、不特定の数またはタイプの引数を取り、何も返さない関数です。 「引数なし」が必要な場合は、次のようにする必要があります。

_void (*functions[256])(void);
_

C++では、void func()doesは「引数を取らない」ことを意味し、混乱を引き起こします(特に、Cがvoid func()に指定する機能は疑わしい値であるため)。

いずれにせよ、関数ポインタをtypedefする必要があります。これにより、コードが非常に理解しやすくなり、構文が間違ってしまう可能性は1回だけです(typedefで)。

_typedef void (*func_type)(void);
// ...
func_type functions[256];
_

とにかく、配列に割り当てることはできませんが、配列を初期化してデータをコピーすることはできます。

_static func_type functions[256] = { /* initializer */ };
memcpy(mystruct.functions, functions, sizeof(functions));
_
21
Chris Lutz

私は同じ問題を抱えていました、これは解決策をテストするための私の小さなプログラムです。とてもわかりやすいように見えるので、将来の訪問者のために共有したいと思いました。

#include <stdio.h>

int add(int a, int b) {
    return a+b;
}

int minus(int a, int b) {
    return a-b;
}

int multiply(int a, int b) {
    return a*b;
}

typedef int (*f)(int, int);                 //declare typdef

f func[3] = {&add, &minus, &multiply};      //make array func of type f,
                                            //the pointer to a function
int main() {
    int i;
    for (i = 0; i < 3; ++i) printf("%d\n", func[i](5, 4));
    return 0;
}
6
Swedgin

あなたはそれを動的に行うことができます...これはmallocで割り当てられた動的関数配列の小さな例です...

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

typedef void (*FOO_FUNC)(int x);

void a(int x)
{
    printf("Function a: %d\n", x);
}

void b(int x)
{
    printf("Function b: %d\n", x);
}

int main(int argc, char **argv)
{
    FOO_FUNC *pFoo = (FOO_FUNC *)malloc(sizeof(FOO_FUNC) * 2);
    pFoo[0] = &a;
    pFoo[1] = &b;

    pFoo[0](10);
    pFoo[1](20);

    return 0;
}
2
TurtleToes

私の頭のてっぺんから、テストされていません。

// create array of pointers to functions
void (*functions[256])(void) = {&function0, &function1, &function2, ..., };

// copy pointers to struct
int i;
for (i = 0; i < 256; i++) struct.functions[i] = functions[i];

[〜#〜] edit [〜#〜]:ChrisLutzが言った構文エラーを修正しました。

1
orlp

post-{func1, func2, ...}のようなフォームを使用して配列を初期化する場合、これは次の方法で実行できます(GCCを使用)。

[〜#〜] upd [〜#〜](ありがとう Chris Lutz コメント)

次のようなマクロを定義します。

#define FUNCTION_VECTOR_COPY(destVec, sourceVec) memcpy(destVec, sourceVec, sizeof(sourceVec))

そして、次のように Compound Literals を使用してソースベクトルを渡します。

#include <string.h>
...
void (*functions[256])();
...
FUNCTION_VECTOR_COPY (functions, ((void(*[])()) {func1, func2, func3}));
0
Martin Babacaev

構造体インスタンスを宣言しながら、これを行うことができます。

function_structur fs = { struct_field1,
                         struct_field2,
                         {function0, function1, ..., function255},
                         struct_field3,
                         ... };

配列が宣言された後、このショートカットを使用して配列を初期化することはできません。これを行う必要がある場合は、動的に行う必要があります(ループ、memcpyなどを使用)。

0
peoro