32

ポインターは、変更可能な (非 const) データまたは定数データへのポインターを指すものとして宣言できます。
ポインターは、関数を指すように定義できます。

const同僚とポインターでの「const」の使用について話し合っていたところ、関数ポインターでの使用に関する質問が出てきました。

ここにいくつかの質問があります:

  1. 定数関数へのポインタと非定数関数へのポインタの意味は何ですか?
  2. 関数を const にすることはできますか?
  3. 関数を非 const (変更可能) にすることはできますか?
  4. 関数ポインタを渡すための適切な (安全な) 構文は何ですか?

編集 1: 関数ポインターの構文

typedef void (*Function_Pointer)(void); // Pointer to void function returning void.

void function_a(Function_Pointer p_func); // Example 1.
void function_b(const Function_Pointer p_func); // Example 2.
void function_c(Function_Pointer const p_func); // Example 3.
void function_d(const Function_Pointer const p_func); // Example 4.

上記の宣言は、関数ポインターを組み込み型へのポインターのように扱う例です。

データ、変数、またはメモリ ポインターを使用すると、上記の組み合わせが可能になります。
したがって、質問は次のとおりです。関数ポインターは同じ組み合わせを持つことができますか、そして const 関数へのポインターは何を意味しますか (例 2 など)?

4

6 に答える 6

59

Cでは、関数が存在するかどうかなどというものはconstないため、const関数へのポインターは無意味です(特定のコンパイラーで確認していませんが、コンパイルしないでください)。

異なりますが、関数への const ポインター、const を返す関数へのポインターなどを使用できることに注意してください。基本的に、関数自体以外はすべて const にすることができます。いくつかの例を考えてみましょう:

// normal pointer to function
int (*func)(int);

// pointer to const function -- not allowed
int (const *func)(int);

// const pointer to function. Allowed, must be initialized.          
int (*const func)(int) = some_func;

// Bonus: pointer to function returning pointer to const
void const *(*func)(int);

// triple bonus: const pointer to function returning pointer to const.
void const *(*const func)(int) = func.

関数へのポインターをパラメーターとして渡す限り、それは非常に簡単です。通常は、正しい型へのポインターを渡すだけです。ただし、任意の型の関数へのポインターを他の型の関数へのポインターに変換してから、元の型に戻し、元の値を保持することができます。

于 2012-04-13T17:59:46.907 に答える
6

C仕様によると(C99、セクション6.7.3):

修飾された型に関連付けられたプロパティは、左辺値である式に対してのみ意味があります。

仕様に「修飾された型」とある場合、それは、、、またはキーワードconstで定義されたものを意味します。スナイス関数は左辺値ではありません。関数のキーワードは意味がありません。ある種のコンパイラ固有の拡張を見ているかもしれません。関数を として宣言しようとすると、一部のコンパイラはエラーをスローします。restrictvolatileconstconst

関数への定数ポインターではなく、定数関数へのポインターを見ていることは確かですか (つまり、関数ではconstなくポインターです)。

#4 について:関数ポインターの作成、受け渡し、および使用に関する役立つ概要については、このガイドを参照してください。

于 2012-04-13T17:54:08.903 に答える
2

C では、関数のようなものはありませんconstconstは型修飾子であるため、関数ではなく型を修飾するためにのみ使用できます。たぶん、関数への const ポインターまたは関数への非 const ポインターを意味しますか?

C++ では、メソッドはconst. もしメソッドconstが したがって、const メソッドと非 const メソッドを指すことができますが、これらのメソッドは異なります。

引数リストで関数ポインタを として受け入れることができますretType (*variableName)(arguments)

[1] そうでない限りmutable

于 2012-04-13T17:48:30.340 に答える
2

C では、GCC の世界にいる場合は関数を使用できます。const関数はconst、関数の宣言やその他のシンボルにアタッチされた属性を使用して宣言できます。これは基本的に、関数の動作に関する情報をコンパイラに提供するために使用されますが、コンパイラが何らかの最適化を実行できるように、関数の本体が利用できない場合でも使用されます。

定数関数は、通常、pure関数の観点から定義されます。

純粋な関数は、基本的に副作用のない関数です。つまり、純粋な関数は、指定されたパラメーターとグローバル メモリに基づいて計算された値を返しますが、他のグローバル変数の値に影響を与えることはできません。純粋な関数は、戻り値の型を合理的に欠くことはできません (つまり、void の戻り値の型を持ちます)。

これで、const 関数とは何かを定義できます。

グローバル メモリにアクセスせず、そのパラメーターのみにアクセスする純粋な関数は、定数関数と呼ばれます。これは、関数がグローバル メモリの状態とは無関係であるため、同じパラメーターを指定すると、常に同じ値が返されるためです。したがって、戻り値は、指定されたパラメーターの値から直接かつ排他的に導出されます。

ここでconstは、関数の可変性については何も意味していません。ただし、グローバルメモリには触れない機能です。このような関数には、通常のポインターを割り当てることができます。とにかく、コード領域は一般的に(しばらくの間自己変更コードを忘れて)ROになり、通常のポインターを介して変更することはできません。

洞察に満ちた記事の全文はこちらからご覧ください。

したがって、GCC 定数関数に関しては、最適化について話しているのであって、関数の可変性について話しているわけではありません。

于 2012-04-13T18:24:47.113 に答える
0

1. 関数の内容を定数にするために 'const' を配置する構文上の場所がありません。

const があるかどうかに関係なく、「関数は左辺値ではありません」というエラーが発生します。

typedef void (* FUNC)(void);
FUNC pFunc;
pFunc = 0;     // OK
*pFunc = 0;    // error:  Cannot assign to a function (a function is not an l-value)

typedef void (* const FUNC)(void);
FUNC pFunc;
pFunc = 0;     // error  (const)
*pFunc = 0;    // error:  Cannot assign to a function (a function is not an l-value)

typedef void (const * FUNC)(void);   // error:  <cv-qualifier>  (lol?)

2 & 3. 関数ポインタ - はい.. 関数の内容は、似ていません。

4. 関数ポインタの受け渡しをより安全にする方法はないと思います。世界のすべての const で保護できる唯一のことは、「SetCallback」がパラメーターの独自のローカル コピーを変更できないことです。

typedef void (* const FUNC)(void);
void SetCallback(const FUNC const pCallback)
{
  FUNC pTemp = pCallback;   // OK  (even though pTemp is not const!!)
  pCallback = 0;            // error  (const)
}
于 2012-04-13T18:15:33.803 に答える
0

1.定数関数へのポインタと非定数関数へのポインタの意味は何ですか?

const と non-const に違いはありません: 関数自体は変更できません。

注: C++ では、関数がクラスのメンバー関数である場合、const は、この関数内のオブジェクトの状態を変更できないことを意味します (メンバー変数が割り当てられ、非 const メンバー関数が呼び出されます)。この場合、 const キーワードはメンバー関数のシグネチャの一部であるため、ポインターに関して違いがあります。

2.関数は const にできますか?

上記を参照。

3.関数を非定数 (変更可能) にすることはできますか?

上記を参照

4.関数ポインタを渡すための適切な (安全な) 構文は何ですか?

フリー関数へのすべてのポインターは、フリー関数への他のポインターにキャストできます (つまり、それらのサイズは同じです)。したがって、(仮想の)関数の型を定義し、void f();すべての関数ポインタをこの型に変換して保存できます。 この共通型を介して関数を呼び出すべきではないことに注意してください。元の関数へのポインター型にキャストする必要があります。そうしないと、未定義の動作が発生します (そしておそらくクラッシュします)。

C++ の場合: メンバー関数へのポインターは、フリー関数へのポインターに変換できるとは限りません。

于 2012-04-13T18:05:56.360 に答える