它是法律和明确定义的行为,使用两个结构之间的转换工会与公共初始序列(见例)? [英] Is it legal and well defined behavior to use a union for conversion between two structs with a common initial sequence (see example)?

查看:120
本文介绍了它是法律和明确定义的行为,使用两个结构之间的转换工会与公共初始序列(见例)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个公开面临一个结构和内部结构B中的API,并需要能够以一个struct乙转换成一个结构A.在以下code法律的和良好定义的行为在C99(2010和VS / C89)和C ++ 03 / C ++ 11?如果是,请解释什么使得它明确界定。如果不是,什么是最有效的,跨平台意味着两个结构之间的转换?

I have an API with a publicly facing struct A and an internal struct B and need to be able to convert a struct B into a struct A. Is the following code legal and well defined behavior in C99 (and VS 2010/C89) and C++03/C++11? If it is, please explain what makes it well-defined. If it's not, what is the most efficient and cross-platform means for converting between the two structs?

struct A {
  uint32_t x;
  uint32_t y;
  uint32_t z;
};

struct B {
  uint32_t x;
  uint32_t y;
  uint32_t z;
  uint64_t c;
};

union U {
  struct A a;
  struct B b;
};

int main(int argc, char* argv[]) {
  U u;
  u.b.x = 1;
  u.b.y = 2;
  u.b.z = 3;
  u.b.c = 64;

  /* Is it legal and well defined behavior when accessing the non-write member of a union in this case? */
  DoSomething(u.a.x, u.a.y, u.a.z);

  return 0;
}

结果
更新

我简化了的例子,写了两个不同的应用。一个基于memcpy和其他利用共用。

I simplified the example and wrote two different applications. One based on memcpy and the other using a union.

结果
联盟:

struct A {
  int x;
  int y;
  int z;
};

struct B {
  int x;
  int y;
  int z;
  long c;
};

union U {
  struct A a;
  struct B b;
};

int main(int argc, char* argv[]) {
  U u;
  u.b.x = 1;
  u.b.y = 2;
  u.b.z = 3;
  u.b.c = 64;
  const A* a = &u.a;
  return 0;
}

结果
的memcpy:

#include <string.h>

struct A {
  int x;
  int y;
  int z;
};

struct B {
  int x;
  int y;
  int z;
  long c;
};

int main(int argc, char* argv[]) {
  B b;
  b.x = 1;
  b.y = 2;
  b.z = 3;
  b.c = 64;
  A a;
  memcpy(&a, &b, sizeof(a));
  return 0;
}

搜索结果
异形大会[DEBUG](X code 6.4,默认的C ++编译器):

下面是在组装调试模式相关的差异。当我异形的发布版本有一个在装配没有区别。

Here is the relevant difference in the assembly for debug mode. When I profiled the release builds there was no difference in the assembly.

结果
联盟:

movq     %rcx, -48(%rbp)

结果
memcpy的:


memcpy:

movq    -40(%rbp), %rsi
movq    %rsi, -56(%rbp)
movl    -32(%rbp), %edi
movl    %edi, -48(%rbp)

搜索结果
警告:

根据工会的例子code产生一个​​关于警告变量'一'是未使用的。由于异形组件可从调试,我不知道是否有任何影响。

The example code based on union produces a warning regarding variable 'a' being unused. As the profiled assembly is from debug, I don't know if there is any impact.

推荐答案

这是好的,因为你正在访问的成员是元素的公共初始序列

This is fine, because the members you are accessing are elements of a common initial sequence.

C11( 6.5.2.3结构和联合成员; 语义

...]如果联合包含共享一个共同的初始序列几种结构(见下文),并且如果联合对象当前包含这些结构中的一个,它允许检查任何它们的共同初始部分任何地方完成型工会的声明是可见的。两种结构共享的公共初始序列如果相应成员具有兼容的类型(并且,对于位字段,相同的宽度)为一个或多个初始成员的序列

[...] if a union contains several structures that share a common initial sequence (see below), and if the union object currently contains one of these structures, it is permitted to inspect the common initial part of any of them anywhere that a declaration of the completed type of the union is visible. Two structures share a common initial sequence if corresponding members have compatible types (and, for bit-fields, the same widths) for a sequence of one or more initial members.

C ++ 03( [class.mem] / 16

如果一个POD联合包含两个或多个POD-结构具有共同的初始序列,并且如果POD联合对象当前包含这些POD-结构之一,它允许检查任何的普通初始部分他们。两POD-结构有着共同的初始序列,如果相应成员具有布局兼容的类型(以及,对于位字段,相同的宽度)为一个或多个初始成员的序列

If a POD-union contains two or more POD-structs that share a common initial sequence, and if the POD-union object currently contains one of these POD-structs, it is permitted to inspect the common initial part of any of them. Two POD-structs share a common initial sequence if corresponding members have layout-compatible types (and, for bit-fields, the same widths) for a sequence of one or more initial members.

的两个标准的其它版本具有类似的语言因为C ++ 11所使用的术语的标准布局的而不是 POD 的。

Other versions of the two standards have similar language; since C++11 the terminology used is standard-layout rather than POD.

我觉得混乱可能已经出现,因为C证的类型夯实的(别名不同类型的成员),通过其中C ++不工会;这是主要的情况下,确保C / C ++的兼容性,你将不得不使用的memcpy 。但是,在你的情况,你要访问的元素具有的相同的类型,是$ P $由兼容类型的成员pceded,所以类型双关的规则是不相关的。

I think the confusion may have arisen because C permits type-punning (aliasing a member of a different type) via a union where C++ does not; this is the main case where to ensure C/C++ compatibility you would have to use memcpy. But in your case the elements you are accessing have the same type and are preceded by members of compatible types, so the type-punning rule is not relevant.

这篇关于它是法律和明确定义的行为,使用两个结构之间的转换工会与公共初始序列(见例)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆