2

C996.2.5P27では

構造体タイプへのすべてのポインタは、互いに同じ表現と配置の要件を持つ必要があります。共用体型へのすべてのポインターは、互いに同じ表現および配置要件を持つ必要があります。他のタイプへのポインタは、同じ表現または配置要件を持つ必要はありません。

これは何を意味するのでしょうか?

構造体タイプへのすべてのポインタは、互いに同じ表現と配置の要件を持つ必要があります。

そして、この例外の理由は何ですか?

他のタイプへのポインタは、同じ表現または配置要件を持つ必要はありません。

関連する例を挙げて説明していただければ幸いです。

4

5 に答える 5

4

これは、任意のポインターから構造体への値を他のポインターから構造体への変数に格納でき、その過程で有効なポインター・オブジェクトを作成し、中間変数から元のポインターを復元できることを意味します。対照的に、別のカテゴリのポインタを中間として使用することは許可されていません。例えば:

struct Foo * p = &x;   // x is a struct Foo
struct Bar * q;

memcpy(&q, &p, sizeof p);  // OK, it's allowed to read (but not dereference!) q
memcpy(&p, &q, sizeof q);  // OK, p is now the same it was before

union Zip * r;
int       * s;

// not allowed to do the same with (p, r) and (p, s)!

両方とも構造体へのポインタであるため、サイズと配置が同じであるため、memcpysはOKです。同じことが、ユニオンへの2つのポインター、またはintへの2つのポインターにも当てはまりますが、カテゴリーを混在させることはできません。pq

別の非常に工夫された、しかし有効な例を次に示します。

struct Foo { int a; };

int f(struct Bar * p)
{
    return (struct Foo *)(p)->a;
}

int main()
{
    Foo x = { 12 };
    return f((struct Bar *)(&x));
}

の関数パラメータが別のカテゴリのポインタ(たとえば、ポインタからユニオンまたはポインタから整数)の場合、このプログラムは無効になります。f

オブジェクトポインタを変換したり戻したりできる唯一のポインタ型はvoid *です。f(したがって、のパラメーターを作成することもできますvoid *。これは間違いなく最も一般的なスタイルです。ただし、構造体ポインターにする方が効率的であるため、一部のプラットフォームでは望ましいと考えられます。)

于 2012-12-28T14:43:40.500 に答える
3

これは、構造体タイプへのポインターを別の構造体タイプへのポインターにキャストすることは、単なる再解釈であることを意味します。

一般に、さまざまなタイプへのポインタのサイズと配置要件は異なることが許可されています。たとえば、char*サイズと配置の要件が16で、アドレスのビッグエンディアンを格納する場合がありますがunsigned long long*、サイズと配置の要件は8とアドレスリトルエンディアンを格納します。

ただし、struct foo *struct bar *の場合、表現と配置の要件は同一である必要があります。(sと同様union

1つの理由は、sに不完全なstructsへのポインタがあるのが一般的であるということですstruct。構造体ポインタの表現と配置の要件が同一でない場合、それは不可能です。

于 2012-12-28T14:41:29.417 に答える
1

ポインタの種類が異なれば、サイズや表現も異なる場合があります。IOWは、int *とはサイズと表現が異なる場合があり、、などとはサイズと表現char *が異なる場合がありますdouble *

どのタイプへのポインタもstruct同じサイズと表現になります。IOW、struct T *およびstruct Q *同じように見えます。ユニオンについても同様でunion T *、同じように見えます(ただし、ポインター union U *とは異なって見える場合があります)。struct

于 2012-12-28T14:42:34.943 に答える
1

非公式言語では、ポインタの表現と変換に関するC言語のセマンティクスの重要な部分は次のとおりです。

  • voidポインタと文字ポインタは表現を共有します
  • すべての構造体ポインタは表現を共有します
  • すべてのユニオンポインタは表現を共有します
  • 任意のオブジェクトポインタ(ただし、一般的には関数ポインタではありません)は、voidポインタまたは文字ポインタに変換して、元の型に戻すことができます。
  • 任意の関数ポインタを他の関数ポインタタイプに変換して、元のタイプに戻すことができます

他のすべては実装次第です。

これらの特定のルールの必要性は、次のように正当化できます。

オブジェクトポインタを文字ポインタに変換すると、タイプに関係なくバイト単位のアクセスが可能になります。voidポインターは基本的には変装した文字ポインターですが、異なるセマンティックな意味合い(型の関連付けのないジェネリックポインター)を持っています。

構造または 表現を共有する共用体ポインターは、不完全な型(不透明なポインター)へのポインターを可能にします。

関数ポインタは、まったく異なるアドレス空間に存在し、バイト単位のアクセスに使用できない可能性があるため、voidポインタに変換できない場合があります。ジェネリック関数ポインター型(voidポインターに相当)がなく、おそらく単一の表現を共有するため、これらは相互に変換可能です。私の知る限り、C標準では単一の表現は必要ありません。つまり、原則として、関数ポインター型間のキャストには実際の変換が含まれる場合があります。ただし、非プロトタイプ関数(および対応する関数ポインター)は、すべての範囲の関数タイプと互換性がある必要があるため、可能な変換は大幅に制限されます。

一般に、C標準は、将来の開発を人為的に制限することなく、幅広い歴史的優先順位に対応するための実装にかなりの任務を残しています。

于 2012-12-28T16:57:40.033 に答える
0

これは、たとえば、関数ポインタの構造や配置に依存できないことを意味します。classこれは、C ++ esまたはsへのポインターを処理するときにそのような仮定を行うことができないことも意味すると思いますstruct(ただし、C ++がこれらをどのように定義するかは確認していません)。

于 2012-12-28T14:41:45.240 に答える