在处理Windows API时,当需要大量数据时,经常会遇到结构。 MSDN文档鼓励在这些结构上使用union punning将它们转换为基本类型。 这些转换是否符合标准,或MSDN是否建议可能导致未定义行为的技术?
例如,当处理FILETIME结构并且需要完成算术时,the MSDN documentation建议:
建议您不要在FILETIME结构中添加和减去值以获取相对时间。相反,您应该将文件时间的低位和高位部分复制到ULARGE_INTEGER结构,对QuadPart成员执行64位算术运算,并将LowPart和HighPart成员复制到FILETIME结构中。
宣布ULARGE_INTEGER
typedef union _ULARGE_INTEGER {
struct {
DWORD LowPart;
DWORD HighPart;
};
struct {
DWORD LowPart;
DWORD HighPart;
} u;
ULONGLONG QuadPart;
} ULARGE_INTEGER, *PULARGE_INTEGER;
那么文档建议的内容,例如计算时间跨度,是这样的:
FILETIME filetime[2];
ULARGE_INTEGER large[2];
// ...
large[0].LowPart = filetime[0].dwLowDateTime;
large[0].HighPart = filetime[0].dwHighDateTime;
large[1].LowPart = filetime[1].dwLowDateTime;
large[1].HighPart = filetime[1].dwHighDateTime;
auto diff = large[1].QuadPart - large[0].QuadPart;
标准中有这个臭名昭着的部分总是出现在类似问题中(引用N3337):
在联合中,最多一个非静态数据成员可以随时处于活动状态,也就是说,任何时候最多一个非静态数据成员的值都可以存储在一个联合中。 [注意:为了简化联合的使用,我们做了一个特别的保证:如果标准布局联合包含几个共享公共初始序列(9.2)的标准布局结构,并且这个标准布局联合类型的对象包含一个标准布局结构,允许检查任何标准布局结构成员的公共初始序列;见9.2。 - 结束说明]
9.2具体指的是结构。
由于ULONGLONG解析为__int64或double,因此ULARGE_INTEGER联合包含两个结构和一个基本类型。在我阅读它时,引用的特殊保证不适用,因为设置HighPart和LowPart以及后续读取QuadPart将设置结构的两个成员然后读取基本类型。引用要求所有包含的实体可以互换地读/写为结构。
MSDN也是如此建议在这种特殊情况下违反标准的技术还是我弄错了?
答案 0 :(得分:2)
严格遵循C ++标准,行为确实是未定义的(正如您的推理)。但是,请记住,标准没有定义,仍然可以通过实现来定义。如果MSDN是用MSVC编译器编写的,那么我就不会感到惊讶,在这种情况下,它可以很好地提供定义的行为。我相信GCC也会声明基于联合的类型惩罚。