Casting one C structure into another

浪尽此生 提交于 2019-12-17 04:52:20

问题


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?


回答1:


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.




回答2:


You could use a pointer to do the typecast;

vector = *((Vector3d *) &acceleration);



回答3:


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



回答4:


Why dont you use.

typedef CMAcceleration Vector3d;

(instead of creating a whole new structure)

in that case vector = acceleration; compiles just fine.




回答5:


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!




回答6:


This is achieved easily through a union:

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

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

typedef union {
    CMAcceleration acceleration;
    Vector3d vector;
} view;

int main() {
    view v = (view) (Vector3d) {1.0, 2.0, 3.0};
    CMAcceleration accel = v.acceleration;
    printf("proof: %g %g %g\n", accel.x, accel.y, accel.z);
}



回答7:


A safe (albeit somewhat convoluted) way to do it would be to use a union:

union { CMAcceleration a, Vector3d v } tmp = { .a = acceleration };
vector = tmp.v;

Values are reinterpreted (since C99) when the accessed member is not the last set one. In this case, we set the acceleration and then we access the vector, so the acceleration is reinterpreted.

This is the way the NSRectToCGRect function is implemented, for example.




回答8:


Another version of the utility function making use of C99:

static inline struct Vector3d AccelerationToVector(struct CMAcceleration In)
{
    return (struct Vector3d){In.x, In.y, In.z};
}

With the compiler optimization turned up (e.g., -Os), this should turn into absolutely no object code when invoked.



来源:https://stackoverflow.com/questions/3995940/casting-one-c-structure-into-another

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!