Programmingシステムプログラマ

Cにおける関数ポインタの宣言と使用の特徴を明らかにしてください。異なる関数のポインタの配列をどのように正しく保存し、動的に呼び出すか?

Hintsage AIアシスタントで面接を突破

回答

Cにおける関数ポインタは、関数のアドレスを格納する変数で、動的にどの関数を呼び出すかを選択することができます。関数ポインタの一般的な宣言:

// intを受け取り、intを返す関数ポインタ int (*f_ptr)(int);

ポインタの配列の場合:

int func1(int x) { return x + 1; } int func2(int x) { return x * 2; } int (*f_arr[2])(int) = { func1, func2 }; int result = f_arr[1](10); // 20を返す
  • このアプローチにより、コマンドテーブルやハンドラを作成したり、操作番号にアクションを自動的に関連付けたりできます。
  • すべての関数は同じシグネチャを持っている必要があります。
  • 関数ポインタを操作する際には、型が正確に一致する必要があります。

ひねりのある質問

関数ポインタを使って異なるシグネチャを持つ関数を呼び出すことは可能ですか?

よくある誤った回答: 「はい、キャストを使えば可能です。」

正しい回答: 技術的には動的な性質のため可能ですが、その行為はランタイムエラーや予測できない動作を引き起こします。なぜなら、異なる呼び出し規約と引数の結合が使用される関数が呼び出されるためです。

例:

void funcA(int x) { printf("A: %d ", x); } void funcB(float y) { printf("B: %f ", y); } void (*fptr)(int) = (void (*)(int)) funcB; fptr(5); // エラー: 不正なデータが渡される

このテーマの詳細を知らないことによる実際のエラーの例


物語

プラグインシステムのプロジェクトで、異なるシグネチャを持つ関数のポインタをテーブルに配置しました(1つはintを返し、もう1つはvoidを返す)。いくつかのアーキテクチャで実行すると、スタックが破損しました。

物語

古いコマンド管理システムで、関数ポインタの配列を使用しました。新人が追加のパラメータを持つ関数を追加し、新しい配列要素に移動した後に予測できない動作を引き起こしました。

物語

ファームウェアでは、関数ポインタの変更結果を確認していませんでした。不十分なハンドラ配列の初期化により、ヌルポインタ(NULL)が呼び出され、デバイスがユーザーに通知されることなくフリーズしました。