C++ 检查联合实例之间是否相等的正确方法是什么?

C++ 检查联合实例之间是否相等的正确方法是什么?,c++,c,unions,C++,C,Unions,我有一个多线程应用程序,它将数据存储为以下联合的实例数组 union unMember { float fData; unsigned int uiData; }; 存储此数组的对象知道union中的数据是什么类型,因此在检索正确类型时,UB没有问题。然而,在程序的其他部分,我需要测试这些联合的两个实例之间的相等性,而在代码的这一部分中,真正的内部数据类型是未知的。这样做的结果是,我无法用这种方法测试联盟的平等性 unMember un1; unMember un2;

我有一个多线程应用程序,它将数据存储为以下联合的实例数组

union unMember {
    float fData;
    unsigned int uiData;
};
存储此数组的对象知道union中的数据是什么类型,因此在检索正确类型时,UB没有问题。然而,在程序的其他部分,我需要测试这些联合的两个实例之间的相等性,而在代码的这一部分中,真正的内部数据类型是未知的。这样做的结果是,我无法用这种方法测试联盟的平等性

  unMember un1;
  unMember un2;
  if (un1 == un2) {
     // do stuff
  }
当我遇到编译器错误时。因此,我只是比较工会的浮动部分

  if (un1.fData == un2.fData) {
     // compiles but is it valid?
  }
现在我已经读到关于UB访问不是上次写入的部分的联盟的任何部分(写得很麻烦,但我想不出更清晰的方式来表达这一点),我想知道上面的代码是否是检查联盟实例平等性的有效方法

这让我意识到,在内部,我不知道工会是如何运作的。我假设数据只是以位模式存储的,您可以根据联合中列出的类型以任何方式解释它如果不是这样,那么测试一个联合的两个实例是否相等的安全/正确方法是什么?


<>最后,我的应用程序是用C++编写的,但是我意识到联盟也是C的一部分,所以它们在2种语言中的处理有什么不同吗?< /P> < P>不同的类型可能有不同的存储长度(两字节和四字节)。 当向工会成员写信时,所能保证的只是写信的成员是正确的

如果然后比较不同的成员,则不知道额外字节中会有什么

测试联合相等性的正确方法是使用一个包含联合和成员的结构,该结构指示当前正在使用的成员,并打开该成员,其中开关的大小写处理每个可能的联合成员的相等性检查,例如,您必须将正在使用的信息与联合一起存储

例如


通常,您需要预先设置当前联合类型的某种指示符:

struct myData
{
    int dataType;
    union {
        ...
    } u;
}
然后:

不管怎样,语法

if (un1.fData == un2.fData) {
    // compiles but is it valid?
}
它可以编译并且是有效的,可能因为两个原因而不起作用。一个是,正如您所说,un2可能包含一个整数而不是浮点。但在这种情况下,平等测试通常会失败。第二个是两个结构都有一个浮点,它们表示相同的数字,但有一点机器错误。然后测试会告诉你数字是不同的(一点一点),而它们的“意义”是相同的

浮点数通常比较如下

if (dabs(f1 - f2) < error)
if(dabs(f1-f2)

避免这个陷阱。C++中的

< P>,不是最后写入的成员被认为是未初始化的(因此读取它们是未定义的行为)。在C中,它们被视为包含写入的成员的对象表示形式,这可能是有效的对象表示形式,也可能不是有效的对象表示形式

就是

union U {
    S x;
    T y;
} u;
u.x = 0;
T t = u.y;    // C++ - reading uninitialized memory - could crash
T t = u.y;    /* C - reading object representation of u.x - could crash */

实践中,如果代码与编写指定成员的代码距离很远,则C++读取一个联合非赋值成员的行为将与C相同,因为编译器唯一的方式来生成不同的代码是优化读写组合。 两种语言中的一种安全方法(保证不会崩溃)是将内存内容作为

char
数组进行比较,例如使用
memcmp

union U u1, u2;
u1.x = 0;
u2.x = 0;

memcmp(&u1, &u2, sizeof(union U));

然而,这可能并不反映工会成员的实际平等;e、 g.对于浮点类型,两个
NaN
值可以具有相同的内存表示形式,并且比较不相等,而
-0.0
0.0
(负零和正零)具有不同的内存表示形式,但比较相等。还有两种类型大小不同的问题,或者包含不参与价值的位(填充位,在大多数现代商品平台上都不是问题)。此外,结构类型可以包含用于对齐的填充。

我认为如果您实现一个类,那么它将是最安全的。如果构造未提供功能(在本例中自动确定要评估的正确成员),则该构造可能不适合您的需要,您应该使用另一个构造;)这可能是一个自定义类,或者如果您使用COM(它基本上是@lserni提出的结构),则可能是一个
变体。

一般来说,您所要求的是不可能的。只有您设置的变量中的内存才能保证是您所期望的。另一个内存基本上是随机的但是,在您的情况下,您可以进行比较,因为所有东西的大小都是相同的。如果我这样做的话,我会比较无符号整数或者做一个memcmp。这一切都取决于一个事实,即工会的所有成员国都有相同的规模。例如,如果您添加双倍,则所有下注都将取消。这属于在C/C++中可以做和不做的一些琐事,但维护起来要困难得多。您正在对工会做出一个假设,需要在代码中明确您做出了这个假设。未来的维护人员可能会搞砸,导致各种难以调试的问题

最好的方法是使用一个带有类型标志的结构,或者使用类似的方法。当使用类似的东西时,您将是未来的自我验证,并使用标准代码,未来的维护人员有机会了解或查看文档


另一个注意事项是,在浮动的情况下,必须定义相等的含义。如果你想要一个模糊的比较,那么你当然需要知道类型。如果你想比较一下,那就很容易了

将联合包装在某个结构中,以记住上次写入哪个字段
union U {
    S x;
    T y;
} u;
u.x = 0;
T t = u.y;    // C++ - reading uninitialized memory - could crash
T t = u.y;    /* C - reading object representation of u.x - could crash */
union U u1, u2;
u1.x = 0;
u2.x = 0;

memcmp(&u1, &u2, sizeof(union U));