tags:

views:

149

answers:

5

I have two identical (but differently named) C structures:

typedef struct {
      double x;
      double y;
      double z;
} CMAcceleration;


typedef struct {
    double x;
    double y;
    double z;   
} Vector3d;

Now I want to assign a CMAcceleration variable to a Vector3d variable (copying the whole struct). How can I do this?

I tried the following but get these compiler errors:

vector = acceleration;           // "incompatible type"
vector = (Vector3d)acceleration; // "conversion to non-scalar type requested"

Of course I can resort to set all members individually:

vector.x = acceleration.x;
vector.y = acceleration.y;
vector.z = acceleration.z;

but that seems rather inconvenient.

What's the best solution?

+7  A: 

You could use a pointer to do the typecast;

vector = *((Vector3d *) &acceleration);
David Gelhar
+1 This is the obvious solution :)
Venemo
It should be pointed out that the compiler is not obliged to ensure that both structs are packed and aligned in the same way.
Oli Charlesworth
This is undefined behaviour because of strict aliasing. http://cellperformance.beyond3d.com/articles/2006/06/understanding-strict-aliasing.html
Secure
@Secure: good link, thanks!
groovingandi
+4  A: 

You use an utility function for that:

void AccelerationToVector( struct CMAcceleration* from, struct Vector3d* to )
{
     to->x = from->x;
     to->y = from ->y;
     to->z = from->z;
}
sharptooth
+12  A: 

That's your only solution (apart from wrapping it into a function):

vector.x = acceleration.x;
vector.y = acceleration.y;
vector.z = acceleration.z;

You could actually cast it, like this (using pointers)

Vector3d *vector = (Vector3d*) &acceleration;

but this is not in the specs and therefore the behaviour depends on the compiler, runtime and the big green space monster.

Georg
+1: Good answer. Describes both the only method that's guaranteed to work, and the method that will usually work in practice, and the reason why this method is technically undefined.
Oli Charlesworth
+1 I would only add that the casting technique is pretty common - it is not like its truly evil.
Amigable Clark Kant
+1 for wrapping it in a function. Even something as trivial as this is well worth making a subroutine for.
alesplin
+3  A: 

memcpy(&vector, &acceleration, sizeof(Vector3d));

Please note that this works only, if the physical layout of the structs in memory are identical. However, as @Oli pointed out, the compiler is not obliged to ensure this!

groovingandi
It should be pointed out that the compiler is not obliged to ensure that both structs are packed and aligned in the same way.
Oli Charlesworth
@Oli Charlesworth: you're right and I updated the answer accordingly
groovingandi
+3  A: 

Why dont you use.

typedef CMAcceleration Vector3d;

(instead of creating a whole new structure)

in that case vector = acceleration; compiles just fine.

SysAdmin
I get a `warning: 'typedef struct Vector3d Vector3d' does not refer to the unqualified type, so it is not used for linkage`. Also in this case, `CMAcceleration` is in a weakly linked framework, so I refrain from using it in my .h file.
Ortwin Gentz
If the `CMAcceleration` struct is coming from a separate framework, you would be best advised to do the field-by-field copy, instead of the memcpy or type-punning tricks, to make your code robust in the event of any future changes in the other framework. (Even if you know the struct layouts are identical today, maybe they won't remain that way in subsequent releases.)
David Gelhar