PODs 的 WinAPI 联合双关语到基本类型:依赖于实现还是符合标准?

WinAPI union punning of PODs to fundamental types: Implementation dependent or standard compliant?

在处理 Windows API 时,人们经常在需要大量数据时偶然发现结构。 MSDN 文档鼓励对这些结构使用联合双关语以将它们转换为基本类型。 这些转换是否符合标准或 MSDN 是否建议可能导致未定义行为的技术?

例如,在处理FILETIME结构体时需要进行运算,the MSDN documentation建议:

It is not recommended that you add and subtract values from the FILETIME structure to obtain relative times. Instead, you should copy the low- and high-order parts of the file time to a ULARGE_INTEGER structure, perform 64-bit arithmetic on the QuadPart member, and copy the LowPart and HighPart members into the FILETIME structure.

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):

In a union, at most one of the non-static data members can be active at any time, that is, the value of at most one of the non-static data members can be stored in a union at any time. [ Note: One special guarantee is made in order to simplify the use of unions: If a standard-layout union contains several standard-layout structs that share a common initial sequence (9.2), and if an object of this standard-layout union type contains one of the standard-layout structs, it is permitted to inspect the common initial sequence of any of standard-layout struct members; see 9.2. — end note ]

9.2特指结构体

由于 ULONGLONG 解析为 __int64 或 double,因此 ULARGE_INTEGER 联合包含两个结构和一个基本类型。在我阅读它时,引用中的特殊保证不适用,因为设置 HighPart 和 LowPart 并随后读取 QuadPart 将设置结构的两个成员,然后读取基本类型。引用要求所有包含的可以互换读取/写入的实体是 structs.

那么 MSDN 是否建议在这种特殊情况下违反标准的技术,还是我理解错了?

严格按照 C++ 标准,行为确实是未定义的(如您所想)。但是,请记住,不是由标准定义的,仍然可以由实现定义。如果 MSDN 是用 MSVC 编译器编写的,我不会感到惊讶,在这种情况下它可以很好地提供定义的行为。我相信 GCC 声明 union-based 类型双关语也被定义。