Как привести C struct просто еще один тип структуры, если их объем памяти равен? - PullRequest
10 голосов
/ 02 мая 2010

У меня есть 2 матричные структуры, которые означают одинаковые данные, но имеют различную форму:

// Matrix type 1.
typedef float Scalar;
typedef struct { Scalar e[4]; } Vector;
typedef struct { Vector e[4]; } Matrix;

// Matrix type 2 (you may know this if you're iPhone developer)
// Defines CGFloat as float for simple description.
typedef float CGFloat;
struct CATransform3D
   {
   CGFloat m11, m12, m13, m14;
   CGFloat m21, m22, m23, m24;
   CGFloat m31, m32, m33, m34;
   CGFloat m41, m42, m43, m44;
};
typedef struct CATransform3D CATransform3D;

Их объемы памяти равны. Поэтому я считаю, что есть способ конвертировать эти типы без каких-либо операций с указателями или копировать так:

// Implemented in external lib.
CATransform3D CATransform3DMakeScale (CGFloat sx, CGFloat sy, CGFloat sz);
Matrix m = (Matrix)CATransform3DMakeScale ( 1, 2, 3 );

Возможно ли это? В настоящее время компилятор выводит сообщение «ошибка: преобразование в запрошенный не скалярный тип».

Ответы [ 2 ]

16 голосов
/ 02 мая 2010

Вероятно, лучшим решением было бы объединить ваши две структуры в союз.Если вы хотите интерпретировать одни и те же данные двумя разными способами, тогда это очевидный выбор.Альтернативой является использование указателей, но это уродливо, нарушает правила псевдонимов и может скрывать ошибки, которые в противном случае могли бы сообщать компилятор.

typedef float Scalar;
typedef struct { Scalar e[4]; } Vector;
typedef struct { Vector e[4]; } Matrix;

struct CATransform3D
{
   CGFloat m11, m12, m13, m14;
   CGFloat m21, m22, m23, m24;
   CGFloat m31, m32, m33, m34;
   CGFloat m41, m42, m43, m44;
};
typedef struct CATransform3D CATransform3D;

typedef union
{
    CATransform3D t;
    Matrix m;
} UMatrix;

CATransform3D CATransform3DMakeScale (CGFloat sx, CGFloat sy, CGFloat sz);
UMatrix um;
um.t = CATransform3DMakeScale ( 1, 2, 3 );
//
// now you can just use um.m when you need to refer to the Matrix type...
//
1 голос
/ 02 мая 2010

Ну, вы можете просто объявить CATransform3DMakeScale следующим образом:

Matrix CATransform3DMakeScale (CGFloat sx, CGFloat sy, CGFloat sz);

C не проверяет тип, чтобы убедиться, что замедление соответствует исходной библиотеке. Если расположение памяти такое же, оно будет работать. Тем не менее, это плохая практика кодирования, и вы должны добавить длинный комментарий, оправдывающий ваши действия ; -)

В противном случае, нет никакого способа обойти это: вы должны использовать указатели или копировать данные. Это будет работать:

CATransform3D m3d = CATransform3DMakeScale ( 1, 2, 3 );
Matrix m;
memcpy(&m, &m3d, sizeof m);

Как вы обнаружили, вы не можете напрямую разыграть структуру. Вы также не можете сделать это:

Matrix m = *(Matrix*) &CATransform3DMakeScale ( 1, 2, 3 );

, поскольку C позволяет использовать оператор & только для значения l.

...