Rozważmy następujący przykład program:Konwersja wskaźnik do struktury do jej pierwszego elementu
#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;
}
skompilowany z:
$ gcc -std=c99 -O2 -Wall -Werror -pedantic -o main main.c
Oczekiwany wynik jest:
$ ./main
a: 4, b: 2
a: 4, b: 2
C99 standard mówi o pierwszym członku struktury:
C99 6.7.2.1 (13): Wskaźnik do obiektu konstrukcji, odpowiednio przekształcony, wskazuje na swój początkowy element ... i odwrotnie. Możliwe jest wypełnienie bez nazwy wewnątrz obiektu struktury, ale nie na jego początku.
W programie przykład wskaźnik do struct embedded
jest przekształcany do wskaźnika do struct base
(poprzez void*
) bez konieczności wyraźnego obsady.
Co, jeśli zamiast tego pierwszy element jest wskaźnikiem bazowym, jak w przypadku struct pointed
? Nie jestem pewien co do obsady w ramach tobase_pointed
. Bez wydrukowanych rzutów śmieci, ale bez ostrzeżeń/błędów kompilacji. Wraz z rzutem drukowane są prawidłowe wartości dla base.a
i base.b
, ale to naprawdę niewiele znaczy, jeśli istnieje niezdefiniowane zachowanie.
Czy obsada do konwersji struct pointed
na pierwszego członka jest poprawna? struct base*
?
Pierwszym elementem 'struct pointed' jest wskaźnik do' struct base'. Będzie to wymagało wyłomu "void * object". Ale nie można usunąć dereferencji 'void *' bez informowania kompilatora o tym, jak usunąć wskaźnik, stąd potrzeba rzutowania. – alvits