Приведение одной структуры С в другую - PullRequest
39 голосов
/ 22 октября 2010

У меня есть две идентичные (но по-разному названные) структуры C:

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


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

Теперь я хочу присвоить переменную CMAcceleration переменной Vector3d (копируя всю структуру).Как я могу это сделать?

Я пробовал следующее, но получаю следующие ошибки компилятора:

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

Конечно, я могу прибегнуть к индивидуальной настройке всех участников:

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

но это кажется довольно неудобным.

Какое лучшее решение?

Ответы [ 8 ]

44 голосов
/ 22 октября 2010

Это ваше единственное решение (кроме преобразования в функцию):

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

Вы могли бы на самом деле разыграть его, как это (используя указатели)

Vector3d *vector = (Vector3d*) &acceleration;

но это не входит в спецификации, и, следовательно, поведение зависит от компилятора, времени выполнения и большого монстра зеленых насаждений.

16 голосов
/ 22 октября 2010

Вы можете использовать указатель, чтобы выполнить тип;

vector = *((Vector3d *) &acceleration);
6 голосов
/ 22 октября 2010

Для этого вы используете служебную функцию:

void AccelerationToVector( struct CMAcceleration* from, struct Vector3d* to )
{
     to->x = from->x;
     to->y = from ->y;
     to->z = from->z;
}
5 голосов
/ 22 октября 2010

Почему вы не используете.

typedef CMAcceleration Vector3d;

(вместо создания совершенно новой структуры)

в этом случае vector = acceleration; компилируется просто отлично.

5 голосов
/ 22 октября 2010

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

Обратите внимание, что это работает, только если физическое расположение структур в памяти идентично. Однако, как указал @Oli, компилятор не обязан это гарантировать!

2 голосов
/ 12 сентября 2017

Это легко достигается с помощью объединения :

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 голос
/ 15 октября 2018

Другая версия служебной функции, использующая C99:

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

Когда включена оптимизация компилятора (например, -Os), это не должно привести к абсолютному отсутствию объектного кода при запуске.

1 голос
/ 27 марта 2017

Безопасный (хотя и несколько запутанный) способ сделать это - использовать объединение:

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

Значения переинтерпретируются (начиная с C99), когда доступ к элементу не является последним установленным. В этом случае мы устанавливаем ускорение, а затем получаем доступ к вектору, поэтому ускорение интерпретируется заново.

Так, например, реализована функция NSRectToCGRect .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...