2016-12-27 1 views
3

効果的なタイプについていくつかのパズルをもう一度見逃しているようです...コードのコメントは本質的に私の質問ですが、この質問を適切なものと考えることができる唯一の方法ですコンテキスト。有効なタイプのルールで混乱しています

私はすべてのことがOKであると思っているのですか、場合によっては間違っていますか?私はこれが複数の質問をする境界線であることを認識していますが、私は本質的に、効果的なタイプと厳密なエイリアシングについての私の理解が正しいかどうかを尋ねています。 GCCは私のために診断を作りませんでした-pedantic-errors -Wextra -Wall -O2 -fstrict-aliasing -Wstrict-aliasing

+2

'buf =(void *)f'は常に' 'f''の型にかかわらず有効です。厳密なエイリアシング規則には' 'char * ''が他の型のエイリアスを許す例外があるからです。 – user3386109

答えて

4

「効果的な型」が適用されることについて、あなたは混乱しているように見えます。これは、ポインタではなく、mallocされたスペースに適用されます。いつものように、ポインタは、ポインターが指し示す可能性のあるスペースとは別のプロパティを持つ別個のオブジェクトです。

fは、(有効な)型の変数であり、その有効な型は常に宣言された型と同じです。すなわち、Foo *です。同様にbufの有効なタイプは常にchar *です。実行時に有効な型が変更される唯一の時間は、動的に割り当てられる領域です。

あなたの箇条書きとコードのコメントはほとんど意味がないので、私はあなたのコードに新たに注釈を付けることに決めました。テキストは、それぞれの場合のテキストの上のコードを指します。

Foo *f = malloc(sizeof(Foo)); 

[OK]をクリックします。初期化されていないバイトが割り当てられ、fがそれらを指しています。動的に割り当てられた領域にはまだ有効な型はありません。

f->n = 1; 

動的に割り当てられたスペースの最初sizeof(int)バイトの有効なタイプは、intに設定されています。

char *buf = malloc(sizeof(Foo)); 
memcpy(buf, f, sizeof(Foo)); 

memcpy機能がコピーされたオブジェクトの有効なタイプを保存 - (*しかし、脚注を参照)ので、スペースの最初sizeof(int)バイトの有効なタイプは、bufによって指さ、intあります。

((Foo *)buf)->n++; 

mallocスペースが正しく任意のタイプのために整列されているので、まず、キャストはアライメント問題はありません。 ((Foo *)buf)->nintの左辺値であり、有効なタイプintのオブジェクトを指定しているため、nのアクセスに移動するとOKです。だから、私たちは問題なく読み書きできます。

memcpy(f, buf, sizeof(Foo)); 

memcpyそれが効果的なタイプを(あなたのコメントはmemcpyのは、いくつかのケースでOKではないかもしれないことを示唆)を設定して、常にOKです。この行は、有効なタイプがintであるため、fで示されるスペースの有効なタイプをintに設定します。

f->n++; 

上記の((Foo *)buf)->n++と同じ原理です。

free(buf); 
buf = (void *)f; 

冗長キャスト。 fが指し示すスペースには有効なタイプintがあります。これらのラインはいずれもそのスペースに書き込まれていないからです。

free(f); 

問題ありません。


脚注:一部の人々が表現f->n(または((Foo *)buf)->n WRT厳しいエイリアシングの異なる解釈を取る彼らはf->n(*f).nのように定義されているため、関連する効果的なタイプは*fの種類、ではないのタイプであることを言います。 f->n私はこの見解に同意しないので、さらに詳しく解説しません。この状況と厳しいエイリアシングの他のグレー領域を明確にするためのC2Xの提案があります。解釈する。

+0

mallocの戻り値を検証する必要があることを追加します。そして、 'Foo * f = malloc(sizeof * f);'は良い習慣です。 – Stargateur

+0

@Stargateur合意。簡潔にするために、私は自分の質問から検証を省き、同じサイズの割り当て、読み込み、書き込みを扱っていたことを強調するために型名を使用しました。それを言及しなかったことに対する謝罪。 :-) –

+0

"f-> nは'(* f).n'として定義されていると言っています... "間違っています。 '* 'と' .'の等価な組み合わせで ' - >'を定義するC++ですが、Cでは定義しません。C言語仕様では' - > '演算子は独立して定義されます。 – AnT

0

コードは有効です。—多形データオブジェクトを扱う必要があるため—はC++の前にどのように行われたかでした。

しかし、足で自分自身を撃つ前に、これらの操作から外挿することはできません。それはFooを持つことから起こり、タイプFoo2は異なるサイズであり、関連付けられたmalloc()が十分に大きくなかったので、そこにない要素にアクセスします。

一般に、ポインタの型が常にmalloc()と同じであれば、それは正しいと思われます。より洗練されたモチズムのために、C++はエラーが発生しにくい(警告が抑制されない限り)可能性があります。

1
// No effective type yet because there has been no write to the memory. 
Foo *f = malloc(sizeof(Foo)); 

ここにはアクセスがなく、オブジェクトもありません。有効なタイプは関係ありません。最初のsizeof(フー)で

// Effective type of `f` is now `Foo *`, except I'm writing to 
// `f->n`, so shouldn't it be `int *`? Not sure what's going on here. 
f->n = 1; 

オブジェクトは、アドレスFでバイト有効なタイプはFooを有し、第1のsizeof(INT)でオブジェクトがアドレスFでバイト有効なint型を有しています。

// No effective type yet because there has been no write to the memory. 
char *buf = malloc(sizeof(Foo)); 

ここにはオブジェクトはありません。有効なタイプは関係ありません。最初のsizeof(フー)で

// Effective type of `buf` is `Foo *`, despite it being declared as 
// `char *`. 
// It's not safe to modify `buf` as a `char` array since the effective type 
// is not `char`, or am I missing something? 
memcpy(buf, f, sizeof(Foo)); 

オブジェクトアドレスにバイトしかし、効果的なタイプのFooを有し、第1のsizeof(INT)でオブジェクトがアドレスにバイトが、有効なint型を有しています。

有効なタイプに関係なく、任意のオブジェクトに文字タイプでアクセスできます。 bufのバイトにcharでアクセスできます。

// The cast here is well defined because effective type of `buf` is 
// `Foo *` anyway, right? 
((Foo *)buf)->n++; 

はい。式全体が有効です。

// I'm not even sure this is OK. The effective type of `buf` is `Foo *`, 
// right? Why wouldn't it be OK then? 
memcpy(f, buf, sizeof(Foo)); 

これは問題ありません。 memcpyは、アドレスfのオブジェクトの型を型Fooに変更します。 fが前にFoo型を持っていなかったとしても、それは今です。

// Safe if the last `memcpy` was safe. 
f->n++; 

はい。

// buf now points to invalid memory. 
free(buf); 

はい。

// Pointers with different declared types point to the same object, 
// but they have the same effective type that is not qualified by 
// `restrict`, so this doesn't violate strict aliasing, right? 
// This is allowed because `f` was allocated via `malloc`, 
// meaning it is suitably aligned for any data type, so 
// the effective type rules aren't violated either. 
buf = (void *)f; 

あなたはコンセプトをミックスしています。個々のポインタの制限と値はエイリアシングには関係ありません。アクセスはです。ポインタbufは単にアドレスfを指します。

// `f`, and consequently `buf` since it points to the same object as `f`, 
// now point to invalid memory. 
free(f); 

はい。

関連する問題