次のプログラム例を検討:期待される出力がその第一の部材に構造体へのポインタを変換
$ gcc -std=c99 -O2 -Wall -Werror -pedantic -o main main.c
:
$ ./main
a: 4, b: 2
a: 4, b: 2
C99でコンパイル
#include <stdio.h>
struct base {
int a, b;
};
struct embedded {
struct base base;
int c, d;
};
struct pointed {
struct base* base;
int c, d;
};
static void base_print(struct base* x) {
printf("a: %d, b: %d\n", x->a, x->b);
}
static void tobase_embedded(void* object) {
base_print(object); // no cast needed, suitably converted into first member.
}
static void tobase_pointed(void* object) {
struct base* x = *(struct base**) object; // need this cast?
base_print(x);
}
int main(void) {
struct embedded em = {{4, 2}};
struct pointed pt = {&em.base};
tobase_embedded(&em);
tobase_pointed(&pt);
return 0;
}
を標準では構造体の最初のメンバーについてこれを示しています:
C99 6.7.2.1(13): 適切に変換された構造体オブジェクトへのポインタは、その最初のメンバを指しています。逆もまた同様です。 構造体オブジェクト内に名前のないパディングがありますが、先頭にはないことがあります。
struct embedded
へのポインタは、明示的なキャストを必要とせず(void*
を通じて)struct base
へのポインタに変換されるプログラム例で
。
代わりに、最初のメンバーがstruct pointed
のようなベースへのポインタの場合はどうなりますか?私はtobase_pointed
のキャストについては不明です。キャストなしではガベージが出力されますが、コンパイルの警告/エラーは出力されません。キャストでは、base.a
とbase.b
の正しい値が表示されますが、未定義の振る舞いがあるかどうかは実際にはあまり意味がありません。
struct pointed
を最初のメンバーに変換するキャストはstruct base*
ですか?
'struct pointed'の最初のメンバーは' struct base'へのポインタです。これは、 'void * object'の逆参照を必要とします。しかし、ポインタを間接参照する方法をコンパイラに知らせずに、 'void *'を逆参照することはできません。したがって、キャストする必要があります。 – alvits