Convert a pointer to a structure to its first member

Consider the following sample program:

#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; } 

Compiled with

 $ gcc -std=c99 -O2 -Wall -Werror -pedantic -o main main.c 

Expected Result:

 $ ./main a: 4, b: 2 a: 4, b: 2 

The C99 standard refers to the first member of the structure:

C99 6.7.2.1 (13): A pointer to a structure object appropriately transformed indicates its initial element ... and vice versa. As a structural object, there may be an unnamed addition, but not at the beginning.

In the example program, a pointer to a struct embedded converted to a pointer to a struct base (via void* ) without the need for an explicit cast.

What if instead the first member is a pointer to the base, as in struct pointed ? I'm not sure what the composition of tobase_pointed . No discarded garbage is printed, but no compilation warnings / errors. The correct values ​​for base.a and base.b will be printed with the cast, but this is not very important if undefined behavior exists.

Is translation to convert struct pointed to its first struct base* element correct?

+8
c
source share
2 answers

The code does not just perform throws, it also shares a pointer to a pointer to the structure structure. This is necessary to get a pointer to the base in the first place.

This is what happens in your code if the tobase_pointed function has been removed:

 struct pointed pt = {&em.base}; void* object = &pt; //pass to the function struct base** bs = object; //the cast in the function assert( bs == (struct base**)&pt ) ; //bs points to the struct pointed assert( bs == &(pt.base) ) ; //bs also points to the initial member struct base* base struct base* b = *bs ; //the dereference in the function base_print(x); 

bs is a pointer that is appropriately converted to point to the starting element. The correct code.

+2
source share

This cast is justified, and you need it because you want to convert a pointer to a pointer to a pointer. If you do not use a throw, dereferencing will be incorrect.

In other words, your base* has the same address as the pt object. This way you can access it through a pointer to pt. But you have to play it.

+1
source share

All Articles