C++ 提取数据的工会

C++ 提取数据的工会,c++,C++,当用作以下用途时,相关工会不会导致UB: union Data { unsigned int intValue; unsigned char argbBytes[4]; }; Data data; data.intValue = 1235347; unsigned char alpha = data.argbBytes[0]; //UB? 我在考虑标准中的9.5/1: 在联合体中,最多一个数据 成员可以随时处于活动状态, 也就是说,值最多为 数据成员可以存储在 任何时候都可以结

当用作以下用途时,相关工会不会导致UB:

union Data
{
    unsigned int intValue;
    unsigned char argbBytes[4];
};
Data data;
data.intValue = 1235347;
unsigned char alpha = data.argbBytes[0]; //UB?
我在考虑标准中的9.5/1:

在联合体中,最多一个数据 成员可以随时处于活动状态, 也就是说,值最多为 数据成员可以存储在 任何时候都可以结婚


我想这是未定义的,因为您所做的是特定于平台的。alpha最终将成为一个不同的值,这取决于您的平台是big-endian还是little-endian

但是,你展示的技巧几乎相当于重新诠释演员阵容

我认为标准指出不能在两个成员中存储不同的值(因为它们在内存中重叠)


发明union的真正原因是为了让人们在更小的内存中存储更多的数据。传统上,与联合一起,您需要在联合外部保存一些标记(可能在位掩码中存储一个或两个位),以记住联合的哪个成员处于活动状态。使用此标记,您应该仔细编写对联合的访问代码,以便只读取活动成员。

通常您是对的,将一种类型的值写入联合,然后将其作为另一种类型读取是未定义的行为。另一方面,iirc标准明确地允许任何东西作为字符数组进行强制转换。我从来没有100%清楚哪个优先,但我使用过的所有实现都允许union casting做你想做的事情。

从文章中不清楚平台上“int”的大小。假设32位整数和8位字符,即sizeof(int)==4

也不清楚机器的末端是什么。让我们假设小端点

在这种情况下,0x12D993(十进制1235347)将存储为

0x93 0xd9 0x12 0x00(递增地址)


当通过“argbBytes”访问此内存时,argbBytes[0]的值实际上取决于机器的端部。因此,它不是未定义的行为,而是实现定义的行为。

是的,它是UB。但它几乎肯定会“起作用”。我就是这么想的;)问题是,执行类似于
(reinterpret_cast(&data.intValue))[0]
的操作也是UB(5.2.10/7)。尽管我很确定通过union从int中提取一个字节在实践中会很好,但我仍然认为它是UB。标准并不是指出int不能同时拥有两个memeber。问题是,一般来说,一个成员的值可能无法转换为另一个成员的值,例如,您可能有一些陷阱位。但是,这种联合技巧不符合“强制转换”的条件,因此,所有内容都可以转换为
char[]
,这一事实与此无关。根据标准,使用这样的联合是UB,但它是如此普遍,以至于编译器倾向于明确地保证它能工作。@jalf标准从来没有明确地说使用这样的联合就是UB。所以对我来说,这看起来就像一个别名,并且明确允许使用
无符号字符
对任何对象使用别名。@Johannes:hmm,公平点。我想你没有一两个关于允许使用
char
别名的参考资料吗?@jalf这是
3.10/15
的最后一个项目。C99在
6.5.2/3
中对此有一个明确的脚注(非规范性),其内容为“如果用于访问联合对象内容的成员与上次用于在对象中存储值的成员不同,该值的对象表示的适当部分被重新解释为新类型中的对象表示,如在6 .6 6中描述的(有时称为“类型双关”)。在规范方面,我的印象是C++和C都具有相同的规格。平台是什么并不重要。标准说这是未定义的行为,所以是UB。特定的编译器可能会保证这一点,但这超出了标准的范围,不能依赖于在每个编译器/平台上工作。@KeithB:请参考标准中的诗句。@chubsdad:错误的方法。如果你不能指出标准的某一部分说它不是,那么它就是未定义的行为。UB是默认值。;)