構造体にポインタを渡すとき、それを受け取る関数は、そのすべてのフィールドのいずれかにアクセスしようとする場合があります。
を受け取った場合、受け取ったポインタに続くstruct something *
任意のバイトを読み取ることができると期待します。sizeof(struct something)
したがって、これらのバイトを自分で予約しないstruct
と、互換性がなくなります-関数が割り当てられていないバイトにアクセスしようとすると、予約されていないメモリにアクセスするため、セグメンテーション違反になるか、別のバイトの構造が破損する可能性がありますデータ。
このプログラムを見てください:
#include <stdlib.h>
#include <stdio.h>
struct __attribute__ ((__packed__)) pair {
short first;
char second;
long int third;
int forth;
char last;
};
void main(void) {
struct pair myPair;
printf("myPair is at 0x%x\n", &myPair);
printf("myPair.first is at 0x%x\n", &(myPair.first));
printf("myPair.second is at 0x%x\n", &(myPair.second));
printf("myPair.third is at 0x%x\n", &(myPair.third));
printf("myPair.forth is at 0x%x\n", &(myPair.forth));
printf("myPair.last is at 0x%x\n", &(myPair.last));
}
そしてサンプル出力:
myPair is at 0xabbd0aa0
myPair.first is at 0xabbd0aa0
myPair.second is at 0xabbd0aa2
myPair.third is at 0xabbd0aa3
myPair.forth is at 0xabbd0aab
myPair.last is at 0xabbd0aaf
ここで学んだことは、各フィールドがメモリ内の前のフィールドの隣、より正確sizeof(previous_field)
には前のフィールドの右側のバイトに格納されることstruct
です(いつ-パックされた理由を理解するためにこれpacked
を参照してくださいが、これは理想的なケースです)。
struct
それで、これと互換性のある別のものを作成したいと想像してください。次のようなものを作成する場合:
struct __attribute__ ((__packed__)) small_pair {
long int first;
char second;
int third;
char forth;
};
次のようにキャストstruct small_pair *
することで、を期待する任意の関数にを渡すことができます。struct pair *
void my_function(struct pair *);
void main(void) {
struct small_pair my_small_pair;
// ...
my_function((struct pair*) &my_small_pair);
// ...
}
void my_function(struct pair *a_pair) {
//...
printf("Second character of pair is %c\n", a_pair->second);
//...
printf("Last character of pair is %c\n", a_pair->last);
//...
}
コンパイルされると、アクセスa_pair->second
は「構造体の開始から2バイト後の1バイトを読み取る」(0xabbd0aa2 - 0xabbd0aa0 = 2
)です。つまり、これは、のフィールドの3番目のバイトになりfirst
ますstruct small_pair
。
しかし、どうa_pair->last
ですか?構造体の0xf
開始から(15)バイトですが、明らかにスペースが不足しています(sizeof(struct small_pair)
わずか14バイト)。
したがって、変数がメモリにロードされる方法によって異なりますが、必要な値を参照していないことは明らかです。最良のケースは、そのアドレスがプロセススペースの外にあるため、セグメンテーションフォールトが発生し、プログラムが異常終了する場合です。しかし、そのメモリの位置に別の変数が宣言されている可能性があります。必要なものとは異なる変数を読み書きし、誰が知っているか、どのような結果になるかを任せます。
したがって、の末尾にさらに2バイトの長さのフィールドを追加するだけで、aのすべての可能な参照が引き続き正しいことstruct small_pair
を保証するため、メモリレベルで互換性があります。struct pair
struct
それでも、セマンティックレベルの互換性は残っていますが、それは別の話です:)