ABRami
ABRami

Reputation: 43

Casting of structures in C when first fields are not aligned

Given two structure in c:

typedef struct _X_
{
   int   virtual_a;
   int   virtual_b;
   void *virstual_c;
   int   a;
   int   b;
   void *c;

    /* More fields to follow */
}X;

typedef struct _Y_
{
   int a;
   int b;
   void *c;

   /* Same fields as in X structure */
}Y;

Q : Is it safe to say that ?

void foo_low( Y *y )
{
   y->a = 1;
   y->b = 2;
}

 void foo( X *x )
 {
   Y *y = (Y *)(&(x->a) )

   foo_low( y );
 }

Is it standard C ? will it work on all compilers ? Is there any problem with padding ?

Upvotes: 0

Views: 143

Answers (3)

James Youngman
James Youngman

Reputation: 3733

No, your function foo won't work, because a is in the wrong place.

Your example is clearly made up and tha's going to reduce the relevance of my answer to the problem you are really trying to solve, but this definition does something like I believe you are asking for:

struct header {
  int a;
  int b;
  void *c;
};

struct shared_fields {
  int a;
  int b;
  void *c;
  /* More fields to follow */
 };

typedef struct 
{
   struct header virtuals;
   struct shared_fields shared;
} X;

typedef struct 
{
   struct shared_fields shared;
} Y;


void foo_low(struct shared *ys)
{
   ys->a = 1;
   ys->b = 2;
}

void foo(X *x)
{
  foo_low(&x->shared);
}

However, this does not perform a cast, since one is not needed. If you really intended to set data via one struct and access it via another, this is not allowed in standard C (though there might be an exception for same-struct-with-different labels as described by Hubert).

I suspect that a better solution to the problem you asked about is the use of union which can often be used to do what you may have in mind. But strictly speaking, if you have an object u of union type and you set u.a, accessing the value of u.b before setting u.b has undefined behaviour. Though commonly people do not worry about that.

Upvotes: 2

Robson França
Robson França

Reputation: 661

That should work. But since you need to access the same fields in two distinct ways (y->a and x->a are different), I would use union:

typedef struct _Y_
{
    int a;
    int b;
    void *c;

   /* Same fields as in X structure */
}Y;


typedef struct _X_
{
     int   virtual_a;
     int   virtual_b;
     void *virstual_c;
     Y    y_fields;     
}X;


typedef union {
    X x;
    Y y;
} Z;

Now x.virtual_a and y.a are in the same memory address.

And you can rewrite your code as follows:

void foo_low( Z *z )
{
   z->y.a = 1;
   z->y.b = 2;
}

void foo( Z *z )
{
   Z *w = z;
   w->y = z->x.y_fields;
   foo_low( w );
}

The only clumsy part is adding Y inside X.

Upvotes: 1

Hubert Schölnast
Hubert Schölnast

Reputation: 8497

if both structs have identically structure it is ok. Names of fields inside the struts need not to be the same, but their types must be the same. Each subfield in X must match to a subfield in Y in its type and position. Names of fields can be different.

Upvotes: 1

Related Questions