web-dev-qa-db-fra.com

Couler une structure C dans une autre

J'ai deux structures C identiques (mais nommées différemment):

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


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

Maintenant, je veux affecter une variable CMAcceleration à une variable Vector3d (en copiant la structure entière). Comment puis-je faire ceci?

J'ai essayé ce qui suit, mais j'ai ces erreurs de compilation:

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

Bien sûr, je peux avoir recours pour définir tous les membres individuellement:

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

mais cela semble plutôt gênant.

Quelle est la meilleure solution?

37
Ortwin Gentz

C'est votre seule solution (à part l'envelopper dans une fonction):

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

Vous pouvez réellement le lancer, comme ceci (en utilisant des pointeurs)

Vector3d *vector = (Vector3d*) &acceleration;

mais ce n'est pas dans les spécifications et donc le comportement dépend du compilateur, du temps d'exécution et du grand monstre de l'espace vert.

40
Georg Schölly

Vous pouvez utiliser un pointeur pour faire la conversion de type;

vector = *((Vector3d *) &acceleration);
16
David Gelhar

Vous utilisez une fonction utilitaire pour cela:

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

Pourquoi n'utilisez-vous pas.

typedef CMAcceleration Vector3d;

(au lieu de créer une toute nouvelle structure)

dans ce cas, vector = acceleration; compile parfaitement.

5
SysAdmin

Ceci est réalisé facilement par un 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);
}
1
johnco

Un moyen sûr (bien que quelque peu compliqué) de le faire serait d'utiliser un syndicat:

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

Les valeurs sont réinterprétées (depuis C99) lorsque le membre auquel on a accédé n'est pas le dernier. Dans ce cas, nous définissons l'accélération puis nous accédons au vecteur afin que l'accélération soit réinterprétée.

C'est la manière dont la fonction NSRectToCGRect est implémentée, par exemple.

Une autre version de la fonction utilitaire utilisant C99:

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

Lorsque l'optimisation du compilateur est activée (par exemple, -Os), cela ne devrait devenir absolument aucun code objet lorsqu'il est appelé. 

0
lundblade