将一个C结构铸造成另一个

Ort*_*ntz 41 c struct casting

我有两个相同(但命名不同)的C结构:

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


typedef struct {
    double x;
    double y;
    double z;   
} Vector3d;
Run Code Online (Sandbox Code Playgroud)

现在我想将一个CMAcceleration变量赋给一个Vector3d变量(复制整个结构).我怎样才能做到这一点?

我尝试了以下但是得到了这些编译错误:

vector = acceleration;           // "incompatible type"
vector = (Vector3d)acceleration; // "conversion to non-scalar type requested"
Run Code Online (Sandbox Code Playgroud)

当然,我可以单独设置所有成员:

vector.x = acceleration.x;
vector.y = acceleration.y;
vector.z = acceleration.z;
Run Code Online (Sandbox Code Playgroud)

但这似乎很不方便.

什么是最好的解决方案?

Geo*_*lly 46

这是你唯一的解决方案(除了将其包装成一个函数):

vector.x = acceleration.x;
vector.y = acceleration.y;
vector.z = acceleration.z;
Run Code Online (Sandbox Code Playgroud)

你可以实际投射它,像这样(使用指针)

Vector3d *vector = (Vector3d*) &acceleration;
Run Code Online (Sandbox Code Playgroud)

但这不在规范中,因此行为取决于编译器,运行时和大绿色空间怪物.

  • +1:好答案。描述了保证可以使用的唯一方法,以及通常在实践中可以使用的方法,以及该方法在技术上未定义的原因。 (3认同)
  • +1我只想补充一点,铸造技术非常常见 - 它并不像它真正邪恶的那样。 (3认同)
  • +1,用于将其包装在函数中。即使是这样琐碎的事情,也值得为其创建子例程。 (2认同)

Dav*_*har 16

您可以使用指针进行类型转换;

vector = *((Vector3d *) &acceleration);
Run Code Online (Sandbox Code Playgroud)

  • 由于严格的别名,这是未定义的行为.http://cellperformance.beyond3d.com/articles/2006/06/understanding-strict-aliasing.html (11认同)
  • 应该指出的是,编译器没有义务确保两个结构以相同的方式打包和对齐. (5认同)

sha*_*oth 6

您使用实用程序功能:

void AccelerationToVector( struct CMAcceleration* from, struct Vector3d* to )
{
     to->x = from->x;
     to->y = from ->y;
     to->z = from->z;
}
Run Code Online (Sandbox Code Playgroud)


小智 6

使用 C99 的实用函数的另一个版本:

static inline struct Vector3d AccelerationToVector(struct CMAcceleration In)
{
    return (struct Vector3d){In.x, In.y, In.z};
}
Run Code Online (Sandbox Code Playgroud)

随着编译器优化的出现(例如,-Os),在调用时这应该变成绝对没有目标代码。


gro*_*ndi 5

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

请注意,如果内存中结构的物理布局相同,则此方法仅适用.但是,正如@Oli指出的那样,编译器没有义务确保这一点!

  • 应该指出的是,编译器没有义务确保两个结构都以相同的方式打包和对齐。 (2认同)

Sys*_*min 5

为什么不用.

typedef CMAcceleration Vector3d;
Run Code Online (Sandbox Code Playgroud)

(而不是创建一个全新的结构)

在那种情况下vector = acceleration;编译就好了.

  • 如果`CMAcceleration`结构来自一个单独的框架,那么最好建议你逐个字段地复制,而不是使用memcpy或type-punning技巧,以便在将来发生任何变化时使代码更加健壮.在另一个框架中.(即使您知道今天的结构布局是相同的,也许它们不会在后续版本中保持这种状态.) (3认同)