正确定义的union和reinterpret_cast之间有什么区别?

use*_*710 11 c++ unions reinterpret-cast

你能否提出至少1个情况,其中存在实质性差异

union {
T var_1;
U var_2;
}
Run Code Online (Sandbox Code Playgroud)

var_2 = reinterpret_cast<U> (var_1)
Run Code Online (Sandbox Code Playgroud)

我对此的想法越多,它们对我来说就越相同,至少从实际的角度来看.

我发现的一个区别是虽然联合大小在大小方面是最大的数据类型,但是这篇文章中描述的reinterpret_cast可能会导致截断,因此普通的旧式C式联合比新的更安全. C++铸造.

你能概述一下这两者之间的区别吗?

Dav*_*eas 8

与其他答案所说的相反,从实际的角度来看,存在巨大差异,尽管标准可能没有这样的差异.

从标准的角度来看,reinterpret_cast只有当中间指针类型的对齐要求不强于源类型的对齐要求时,才能保证可以用于往返转换.不允许(*)读取一个指针并从另一个指针类型读取.

同时,该标准需要来自联合的类似行为,从活动成员(最后写入的成员)(+)之外读取联合成员是未定义的行为.

然而编译器经常为union案例提供额外的保证,我所知道的所有编译器(VS,g ++,clang ++,xlC_r,intel,Solaris CC)保证你可以通过一个非活动成员读出一个union并且它会生成一个与通过活动成员写入的位设置完全相同的值.

在从网络读取时进行高度优化时,这一点尤为重要:

double ntohdouble(const char *buffer) {          // [1]
   union {
      int64_t   i;
      double    f;
   } data;
   memcpy(&data.i, buffer, sizeof(int64_t));
   data.i = ntohll(data.i);
   return data.f;
}
double ntohdouble(const char *buffer) {          // [2]
   int64_t data;
   double  dbl;
   memcpy(&data, buffer, sizeof(int64_t));
   data = ntohll(data);
   dbl = *reinterpret_cast<double*>(&data);
   return dbl;
}
Run Code Online (Sandbox Code Playgroud)

[1]中的实现由我所知道的所有编译器(gcc,clang,VS,sun,ibm,hp)批准,而[2]中的实现不是,并且当使用积极优化时,其中一些实现失败.特别是,我已经看到gcc重新排序指令并在评估ntohl之前dbl变量,从而产生错误的结果.


(*)除了不管真实对象(原始指针类型)是什么,总是允许你从a 读取[signed|unsigned] char*.

(+)除了一些例外,如果活动成员与另一个成员共享一个公共前缀,您可以通过兼容成员读取该前缀.

  • @MarcClaesen:谷歌严格别名和一些直言不讳的话,你会发现有人在GCC中抱怨这种行为.该标准为有效别名*(指向同一对象的多个指针)提供了一组情境,在有限集之外,其他一切都是未定义的行为,上面的`reinterpret_cast`的情况是未定义的行为.有关详细信息,请参阅google*'严格别名','无严格别名'*或类似内容 (2认同)

Joh*_*ing 5

正确union和(假设)正确和安全之间存在一些技术差异reinterpret_cast.但是,我想不出任何无法克服的差异.

在我看来,偏爱结束的真正原因不是技术性的.这是为了文档.unionreinterpret_cast

假设您正在设计一组类来表示有线协议(我猜这是首先使用类型惩罚的最常见原因),并且该有线协议由许多消息,子消息和字段组成.如果这些字段中的一些是常见的,例如msg类型,seq#等,则使用union简化了将这些元素绑定在一起并有助于准确记录协议在线路上的显示方式.

reinterpret_cast显然,使用同样的事情,但为了真正知道发生了什么,你必须检查从一个数据包前进到下一个数据包的代码.使用union你可以看看标题,并了解正在发生的事情.