web-dev-qa-db-ja.com

関数ポインタのサイズについて何が保証されていますか?

Cでは、関数ポインタが含まれている構造体のサイズを知る必要があります。すべてのプラットフォームとアーキテクチャで次のことを保証できますか?

  • void *のサイズは関数ポインタと同じサイズですか?
  • 関数ポインタのサイズは、その戻り値の型によって異なりませんか?
  • 関数ポインタのサイズは、そのパラメータタイプによって異なりませんか?

答えはこれらすべてにイエスだと思いますが、確かにしたいと思います。コンテキストとして、私はsizeof(struct mystruct)と呼んでいます。

30
Paul Biggar

C99仕様、セクション6.2.5、パラグラフ27から:

Voidへのポインタは、文字タイプへのポインタと同じ表現および配置要件を持つ必要があります。同様に、互換性のあるタイプの修飾バージョンまたは非修飾バージョンへのポインタは、同じ表現および配置要件を持つ必要があります。構造タイプへのすべてのポインタは、互いに同じ表現と配置の要件を持つ必要があります。共用体タイプへのすべてのポインターは、互いに同じ表現および配置要件を持つ必要があります。他のタイプへのポインタは、同じ表現または配置要件を持つ必要はありません。

だからいいえ。 void *関数ポインタを保持できます。

そしてセクション6.3.2.3、パラグラフ8:

あるタイプの関数へのポインターを別のタイプの関数へのポインターに変換して、元に戻すことができます。結果は元のポインタと同じになります。

1つの関数ポインター型が他の関数ポインター値を保持できることを意味します。技術的には、これは関数ポインタ型のサイズが変化しないことを保証することと同じではなく、単にそれらの値が互いに同じ範囲を占めることを保証することです。

32

ダメダメダメ。

Cは、コードとデータポインタのサイズが異なるハーバードアーキテクチャを好みません。このようなアーキテクチャをプログラミングする場合、理想的にはデータをプログラムメモリ(文字列リテラルなど)に格納する必要があり、そのためにはオブジェクトポインタが必要になるためです。コードスペース。ただし、標準に関する限り、関数ポインタはデータアドレス空間とは異なるサイズのアドレス空間を参照できます。

ただし、任意のオブジェクトポインタをvoid*にキャストして戻すことができるのと同じように、任意の関数ポインタを別の関数ポインタタイプ[*]にキャストして、値を破棄せずに戻すことができます。したがって、関数ポインタのサイズがシグネチャに応じて変化するのはかなり驚くべきことです。どういうわけか同じ値をより少ないスペースに格納し、キャストバック時にそれを取得できる必要がある場合、余分なスペースの明確な「使用」はありません。

[*]ありがとう、ショット。

15
Steve Jessop

他の答えに加えて、ウィキペディアはこれを言います:

http://en.wikipedia.org/wiki/Function_pointer

CおよびC++の関数ポインターは単純なアドレスとして実装できるため、通常はsizeof(Fx)==sizeof(void *)ですが、C++のメンバーポインターは「ファットポインター」として実装されることが多く、通常は単純な関数ポインターの2〜3倍のサイズです。 、仮想継承を処理するため。

関数ポインタは抽象化です。規格の要件が満たされている限り、何でも可能です。つまりプログラムに256未満の関数がある場合、関数ポインターは、NULLの場合は値0、物理アドレスを持つテーブルへのインデックスとして値1〜255の1バイトを使用して実装できます。 255関数を超える場合は、2バイトを使用するように拡張できます。

9
Secure

以前は一般的だったさまざまなサイズの実際的な例があります。 MS-DOSおよび初期のWindowsCプログラミングでは、「中」メモリモデルには16ビットのデータポインタがありましたが、32ビットの関数ポインタがありました。「コンパクト」メモリモデルはその逆でした。

2
ErkkiRuohtula