C言語で作り込んだ複数の自作関数があります。
アプリケーション次第で実行順序が変わる可能性があるため、外部ファイル(CSVファイル)に関数名や引数を記載し実行順序を管理したいと考えています。
初期化の処理でCSVファイルを読み、関数の数に従い動的に配列を確保、関数名を配列に読み込みます。
関数ポインタを使って各関数を実行する仕組みを想定していますがこのアプローチで問題ないか、その記述方法は、等アドバイス頂けると助かります。(簡単なサンプルがあると非常に助かります)
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/01/19 11:01
回答6件
0
呼び出し対象となる関数は以下の形とします。
double MyFunc1(int a, int b)
double MyFunc2(int a, int b)
double MyFunc3(int a, int b)
a,bは入力パラメータ、戻り値はdouble型とします。
以下の内容のテキストファイルを定義しておきます。(CSV形式のファイルでも良い)
MyFunc2 20 21
MyFunc1 10 11
MyFunc3 30 31
上記の設定ファイルを読み込み、
MyFunc2(20,21)
MyFunc1(10,11)
MyFunc3(30,31)
の順に呼び出すことを実現します。
各関数の戻り値はdouble型で、その結果を表示します。
(戻り値に対して更にチェックが必要であれば、その機能も付加することは可能だが、
特にそのような要件が提示されていないので、戻り値を表示するのみとします)
下記がそのサンプルです。
ファイルのデータは、読み込まず、読み込んだものとして、テーブルに
直接データを格納しています。
関数未定義の試験を行う場合は、
strcpy(cfunc[0].name,"MyFunc2");
の個所を
strcpy(cfunc[0].name,"MyFuncXX");
等に変えてコンパイルしてください。
C
1#include <stdio.h> 2#include <string.h> 3 4//関数呼出テーブル 5typedef struct _tCALL_FUNC 6{ 7 char name[32]; //関数名 8 int p1; //引数1 9 int p2; //引数2 10 double ret; //戻り値の判定用 11 //戻り値の用途が不明なのでとりあえず1つ定義 12 //特に使用しない 13 double (*funcAddr)(int,int); 14} CALL_FUNC; 15// 関数定義テーブル 16typedef struct _tFUNC { 17 char *name; //関数名 18 double (*Func)(int,int); //関数へのポインター 19} FUNC; 20 21//サンプル関数 22double MyFunc1(int a,int b) 23{ 24 printf("MyFunc1:p1=%d p2=%d\n",a,b); 25 return 1.0; 26} 27double MyFunc2(int a,int b) 28{ 29 printf("MyFunc2:p1=%d p2=%d\n",a,b); 30 return 2.0; 31} 32double MyFunc3(int a,int b) 33{ 34 printf("MyFunc3:p1=%d p2=%d\n",a,b); 35 return 3.0; 36} 37 38FUNC func_tbl[]={ 39 { "MyFunc1",MyFunc1 }, 40 { "MyFunc2",MyFunc2 }, 41 { "MyFunc3",MyFunc3 }, 42}; 43 44int no_func_tbl = sizeof(func_tbl) / sizeof(FUNC); 45//関数名から関数へのポインターを取得する 46void *GetFunc(char *name) 47{ 48 int i; 49 for (i = 0; i < no_func_tbl;i++){ 50 if (strcmp(name,func_tbl[i].name)==0){ 51 return func_tbl[i].Func; 52 } 53 } 54 return NULL; 55} 56int main(void) 57{ 58 int func_count = 3; 59 double retval; 60 int p1; 61 int p2; 62 CALL_FUNC cfunc[256]; 63 double (*addr)(int,int); 64 int i; 65 //本来はCSVファイル又はテキストファイルを読み込んで設定する 66 strcpy(cfunc[0].name,"MyFunc2"); 67 cfunc[0].p1 = 20; 68 cfunc[0].p2 = 21; 69 strcpy(cfunc[1].name,"MyFunc1"); 70 cfunc[1].p1 = 10; 71 cfunc[1].p2 = 11; 72 strcpy(cfunc[2].name,"MyFunc3"); 73 cfunc[2].p1 = 30; 74 cfunc[2].p2 = 31; 75 //関数へのポインター取得 76 for (i = 0; i < func_count;i++){ 77 addr = GetFunc(cfunc[i].name); 78 if (addr == NULL){ 79 printf("関数未定義:%s\n",cfunc[i].name); 80 return 10; 81 } 82 cfunc[i].funcAddr = addr; 83 } 84 //関数の呼び出し 85 for (i = 0; i < func_count;i++){ 86 addr = cfunc[i].funcAddr; 87 p1 = cfunc[i].p1; 88 p2 = cfunc[i].p2; 89 //実際の関数の呼び出し 90 retval = (*addr)(p1,p2); 91 //戻り値の印字&格納 92 cfunc[i].ret = retval; 93 printf("name=%s retval=%f\n",cfunc[i].name,retval); 94 } 95 return 0; 96} 97
以下、実行結果です。
MyFunc2:p1=20 p2=21
name=MyFunc2 retval=2.000000
MyFunc1:p1=10 p2=11
name=MyFunc1 retval=1.000000
MyFunc3:p1=30 p2=31
name=MyFunc3 retval=3.000000
投稿2021/01/19 13:24
編集2021/01/19 13:26総合スコア5493
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
ベストアンサー
C
1#include <stdio.h> // fopen, fclose, fscanf, puts, printf, perror 2#include <string.h> // strcmp 3 4struct FuncTable { 5 const char *fname; 6 int (*func)(int, int); 7}; 8 9int add(int a, int b) { printf("%d + %d", a, b); return a + b; } 10int sub(int a, int b) { printf("%d - %d", a, b); return a - b; } 11int mul(int a, int b) { printf("%d * %d", a, b); return a * b; } 12 13struct FuncTable ftab[3] = { 14 { "add", add }, 15 { "sub", sub }, 16 { "mul", mul }, 17}; 18 19int main(void) 20{ 21 FILE *fp = fopen("seq.csv", "r"); 22 if (!fp) { perror("seq.csv"); return 1; } 23 char fname[32]; 24 int a, b, i; 25 while (fscanf(fp, " %31[^,],%d,%d", fname, &a, &b) == 3) { 26 for (i = 0; i < 3 && strcmp(fname, ftab[i].fname); i++) ; 27 if (i == 3) puts("funcion not found"); 28 else printf(" = %d\n", ftab[i].func(a, b)); 29 } 30 fclose(fp); 31}
seq.csv
text
1add,10,20 2sub,33,55 3mul,44,6 4sub,123,23 5mul,-9,8 6add,-77,30
実行結果
text
110 + 20 = 30 233 - 55 = -22 344 * 6 = 264 4123 - 23 = 100 5-9 * 8 = -72 6-77 + 30 = -47
投稿2021/01/19 15:06
総合スコア8224
0
コメントで書かれている
CSVファイルから読み込んだ関数名は配列に入っているとするとどのように関数ポインタを使えば良いかがわかりません。
以下は、そのへんをガッツリやるのであれば…という話です。
関数名文字列から関数ポインタを特定するのであれば、Linuxの場合dlopen()やdlsym()あたりを使えば実現できます。(その他OSの場合の事情はわかりませんが多分同様の関数があるんじゃないかと思います。)
本体プログラム作成時に確定していないライブラリを後からプラグイン出来るようなものを実現するのに使われていると思います。
ただしその場合でも、実行時に任意の関数を勝手に呼ぶことが出来るわけではなく引数や戻り値などの関数スペックはコンパイル時の段階で決定されている必要があります。
引数について未確定な場合、ダミーの「void*」型の引数を多数用意した関数を使うことにして、呼び出し元と呼び出し先の関数でキャストして無理やり辻褄を合わせるようなことが行われるようです。
投稿2021/01/19 11:14
総合スコア1248
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
やりたいことが漠然としすぎているので、「そういう方法も良いでしょう」という以上は言いようが無いです。
関数名と関数ポインターを対応付けた配列をあらかじめ作っておくのでしょうね。
投稿2021/01/19 09:53
総合スコア85886
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。