次のコードは、実行時にマイクロプロセッサをクラッシュさせます。
struct dummytype dummy;
struct crummytype crummy;
*(unsigned int*)&dummy = *(unsigned int*)&crummy;
両方の構造体が同じサイズであると仮定すると、このコードに有効な C ではない何かがありますか? その有効性は何か特定のものに左右されますか?
次のコードは、実行時にマイクロプロセッサをクラッシュさせます。
struct dummytype dummy;
struct crummytype crummy;
*(unsigned int*)&dummy = *(unsigned int*)&crummy;
両方の構造体が同じサイズであると仮定すると、このコードに有効な C ではない何かがありますか? その有効性は何か特定のものに左右されますか?
これは、両方の構造体がunsigned int
最初のメンバーとして を持っている場合にのみ有効です。
C99 §6.7.2.1/13
構造体オブジェクト内では、ビットフィールド以外のメンバーとビットフィールドが存在するユニットには、宣言された順序で増加するアドレスがあります。適切に変換された構造体オブジェクトへのポインターは、その最初のメンバー (または、そのメンバーがビットフィールドの場合は、それが存在するユニット) を指し、その逆も同様です。構造体オブジェクト内に名前のないパディングがある場合がありますが、先頭にはありません。
簡単に言えば、構造体オブジェクトのアドレスを指定すると、そのアドレスを最初のメンバー型へのポインターにキャストできます。
struct A
{
unsigned int n;
char junk[5];
};
struct A a;
unsigned int *p = (unsigned int *)&a; // OK. pointer is proper for first member type
unsigned long*x = (unsigned long *)&a; // BAD
つまり、両方の構造体の型unsigned int
に最初のメンバーが含まれている場合にのみ、コードは正当です。それ以外はすべて未定義の動作です(void *
耐えられませんが、逆参照できないため、ここでは実際には適用できません)。を保持するのに「十分な大きさ」の各構造タイプでは十分でunsigned int
はありません。それらの最初のメンバーは、実際にはunsigned int
.
両方の構造体が同じサイズであっても、重なり合う動作は未定義です。
構造がこのようなものである場合、上記のステートメントは、探している結果をもたらします。
struct dummytype
{
int a;
};
struct crummytype
{
int b;
};
構造がこのようなものである場合、結果がどうなるかは言えません。
struct dummytype
{
char name[20];
int a;
};
struct crummytype
{
char name1[20];
int b;
};
C99 ドラフト標準の状態 (附属書 J):
J.2 未定義の動作
次の状況では、動作は未定義です。
[...] オブジェクトは、不正確に重複するオブジェクト、または互換性のないタイプ (6.5.16.1) で正確に重複するオブジェクトに割り当てられます。
次に、互換性のある型に関するものについて:
6.2.7 互換型と複合型
型が同じ場合、2 つの型には互換性のある型があります。2 つの型に互換性があるかどうかを判断するための追加の規則は、型指定子については 6.7.2 で、型修飾子については 6.7.3 で、宣言子については 6.7.5 で説明されています。さらに、別々の翻訳単位で宣言された 2 つの構造体、共用体、または列挙型は、それらのタグとメンバーが次の要件を満たしている場合に互換性があります。両方とも完全な型である場合、次の追加要件が適用されます。対応するメンバーの各ペアが互換性のある型で宣言され、対応するペアの 1 つのメンバーが名前で宣言されている場合、他のメンバーは同じ名前で宣言されています。2 つの構造体の場合、対応するメンバーは同じ順序で宣言する必要があります。2 つの構造体または共用体の場合、対応するビット フィールドの幅は同じでなければなりません。2 つの列挙の場合、対応するメンバーは同じ値を持つ必要があります。
2 つの構造体を同じサイズにするだけでは、互換性のある型にするのに十分ではないため、動作は未定義です。
編集:完全を期すために、@PascalCuoqがコメントで引用した抜粋をこのスレッドの別の回答に追加します。これも関連しています:
6.5 式
[...]
7
オブジェクトは、次の型のいずれかを持つ左辺値式によってのみアクセスされる格納された値を持つものとします。
- オブジェクトの有効な型と互換性のある型、
- オブジェクトの有効な型と互換性のある修飾された型のバージョン、
- オブジェクトの有効な型に対応する符号付きまたは符号なしの型である型、
- オブジェクトの有効な型の修飾されたバージョンに対応する符号付きまたは符号なしの型である型、
- 前述のタイプのいずれかをメンバーに含む集約型または共用体型 (再帰的に、サブ集約または含まれる共用体のメンバーを含む)、または
- 文字タイプ。