🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

CSV

CSV(Comma-Separated Values)はコンマで区切られた明白なテキスト値のリストです。もしくは、そのフォーマットでひとつ以上のリストを含むファイルを指します。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

6回答

1180閲覧

C言語で実行する関数の順番をCSVファイルで管理したい

e46

総合スコア3

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

CSV

CSV(Comma-Separated Values)はコンマで区切られた明白なテキスト値のリストです。もしくは、そのフォーマットでひとつ以上のリストを含むファイルを指します。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2021/01/19 08:34

C言語で作り込んだ複数の自作関数があります。
アプリケーション次第で実行順序が変わる可能性があるため、外部ファイル(CSVファイル)に関数名や引数を記載し実行順序を管理したいと考えています。
初期化の処理でCSVファイルを読み、関数の数に従い動的に配列を確保、関数名を配列に読み込みます。
関数ポインタを使って各関数を実行する仕組みを想定していますがこのアプローチで問題ないか、その記述方法は、等アドバイス頂けると助かります。(簡単なサンプルがあると非常に助かります)

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tatsu99

2021/01/19 09:09 編集

各関数の引数の型(及び入力/出力)、引数の数は全て同じですか。それともバラバラですか。 戻り値の型についてもどうでしょうか。 もし、全て同じなら、それを提示してください。 もし、バラバラなら、いくつか代表的なサンプルを提示してください。 私が回答できるわけではありませんが、良い回答が得られ易くなるかと。
e46

2021/01/19 11:01

引数の型、引数の数、戻り値の型、 すべて同じです。 例えば、double myFunc1(int a, int b)のような感じです。
guest

回答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
tatsu99

総合スコア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

kazuma-s

総合スコア8224

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

e46

2021/01/21 12:04

わかりやすいサンプルありがとうございます。大変助かりました。
guest

0

具体的な実現方法はすでに回答されていると思うのですが。。

通常プログラムというのは、機能を提供するものです。
そして、機能を外部から変更したい場合によく利用されるのが、オプションと呼ばれる(コマンドライン)引数だったりします。
まぁ、プログラマブルなレゴブロックみたいで面白いとは思いますが、そこまで汎用的にしたいユースケースが思いつきません。
まして、スクリプト系の言語ではなく、C/C++で実現したいというであれば尚更です。

投稿2021/01/20 01:45

t_obara

総合スコア5488

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

コメントで書かれている

CSVファイルから読み込んだ関数名は配列に入っているとするとどのように関数ポインタを使えば良いかがわかりません。

以下は、そのへんをガッツリやるのであれば…という話です。

関数名文字列から関数ポインタを特定するのであれば、Linuxの場合dlopen()やdlsym()あたりを使えば実現できます。(その他OSの場合の事情はわかりませんが多分同様の関数があるんじゃないかと思います。)
本体プログラム作成時に確定していないライブラリを後からプラグイン出来るようなものを実現するのに使われていると思います。

ただしその場合でも、実行時に任意の関数を勝手に呼ぶことが出来るわけではなく引数や戻り値などの関数スペックはコンパイル時の段階で決定されている必要があります。

引数について未確定な場合、ダミーの「void*」型の引数を多数用意した関数を使うことにして、呼び出し元と呼び出し先の関数でキャストして無理やり辻褄を合わせるようなことが行われるようです。

投稿2021/01/19 11:14

hidezzz

総合スコア1248

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

やりたいことが漠然としすぎているので、「そういう方法も良いでしょう」という以上は言いようが無いです。
関数名と関数ポインターを対応付けた配列をあらかじめ作っておくのでしょうね。

投稿2021/01/19 09:53

otn

総合スコア85886

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

e46

2021/01/19 10:34

プログラムをリコンパイルすることなく、自作関数の実行順序を変更するためCSVファイルで管理するアイデアです。CSVファイルから読み込んだ関数名は配列に入っているとするとどのように関数ポインタを使えば良いかがわかりません。その他良い方法はありますでしょうか?
otn

2021/01/19 10:46

やりたいこと次第でしょうね。
guest

0

関数名や変数名はコンパイル結果には一切含まれません
なので、関数ポインタを配列に入れ、そのインデックスで指定するようにするのがいいかと

投稿2021/01/19 08:40

y_waiwai

総合スコア88038

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問