web-dev-qa-db-de.com

Eine C-Struktur in eine andere gießen

Ich habe zwei identische (aber unterschiedlich benannte) C-Strukturen:

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


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

Jetzt möchte ich einer Vector3d-Variablen eine CMAcceleration-Variable zuweisen (die gesamte Struktur kopieren). Wie kann ich das machen?

Ich habe folgendes versucht, bekomme aber folgende Compiler-Fehler:

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

Natürlich kann ich alle Mitglieder einzeln einstellen:

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

aber das scheint ziemlich unbequem zu sein.

Was ist die beste Lösung?

37
Ortwin Gentz

Das ist Ihre einzige Lösung (abgesehen von einer Funktion in einer Funktion):

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

Man könnte es tatsächlich so wirken (mit Zeigern)

Vector3d *vector = (Vector3d*) &acceleration;

dies ist jedoch nicht in den Spezifikationen enthalten und daher hängt das Verhalten vom Compiler, der Laufzeit und dem großen Grünflächenmonster ab.

40
Georg Schölly

Sie können einen Zeiger verwenden, um die Typumwandlung durchzuführen.

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

Sie verwenden dazu eine Utility-Funktion:

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

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

Bitte beachten Sie, dass dies nur funktioniert, wenn das physikalische Layout der Strukturen im Speicher identisch ist. Allerdings ist der Compiler, wie @Oli betont hat, nicht verpflichtet, dies sicherzustellen!

5
groovingandi

Warum verwenden Sie nicht?.

typedef CMAcceleration Vector3d;

(anstatt eine ganz neue Struktur zu erstellen)

in diesem Fall wird vector = acceleration; gut kompiliert.

5
SysAdmin

Dies wird leicht durch eine union erreicht:

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

Eine sichere (wenn auch etwas verschlungene) Möglichkeit, dies zu tun, wäre die Verwendung einer Gewerkschaft:

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

Werte werden neu interpretiert (seit C99), wenn das aufgerufene Element nicht das letzte festgelegte ist. In diesem Fall setzen wir die Beschleunigung und greifen dann auf den Vektor zu, sodass die Beschleunigung neu interpretiert wird.

So wird beispielsweise die Funktion NSRectToCGRect implementiert.

Eine andere Version der Utility-Funktion, die C99 verwendet:

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

Wenn die Compiler-Optimierung aktiviert ist (z. B. -Os), sollte dies beim Aufruf zu keinerlei Objektcode werden. 

0
lundblade