如果内存大小相等,如何将 C 结构体转换为另一种结构体类型?

发布于 2024-08-31 11:54:12 字数 812 浏览 5 评论 0原文

我有 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 );

这可能吗?当前编译器打印一条“错误:请求转换为非标量类型”消息。

I have 2 matrix structs means equal data but have different form like these:

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

Their memory sizes are equal. So I believe there is a way to convert these types without any pointer operations or copy like this:

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

Is this possible? Currently compiler prints an "error: conversion to non-scalar type requested" message.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

彼岸花ソ最美的依靠 2024-09-07 11:54:12

也许最好的解决方案是将两个结构组合成一个联合。如果您想以两种不同的方式解释相同的数据,那么这是显而易见的选择。另一种方法是使用指针强制转换,但这很丑陋,破坏了别名规则,并且可以隐藏编译器可能报告的错误。

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...
//

Probably the best solution would be to combine your two structs into a union. If you want to interpret the same data in two different ways then it's the obvious choice. The alternative is to use pointer casts, but that's ugly, breaks aliasing rules, and can hide errors that might otherwise be reported by the compiler.

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...
//
煮酒 2024-09-07 11:54:12

好吧,您可以像这样声明 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 只允许你使用 &左值运算符。

Well, you could just declare CATransform3DMakeScale like this:

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

C doesn't type-check to make sure your deceleration matches the original library. If the memory layout is the same, it will work. However, it's bad coding practice and you should include a lengthy comment justifying your actions. ;-)

Otherwise, there's no way around it: you have to use pointers or copy the data. This would work:

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

As you've discovered, you can't cast the structure directly. You also can't do this:

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

because C only allows you to use the & operator on an l-value.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文