WinAPI将POD与基本类型联合起来:依赖于实现还是符合标准?

时间:2016-01-14 16:50:11

标签: c++ winapi visual-c++ language-lawyer type-punning

在处理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也是如此建议在这种特殊情况下违反标准的技术还是我弄错了?

1 个答案:

答案 0 :(得分:2)

严格遵循C ++标准,行为确实是未定义的(正如您的推理)。但是,请记住,标准没有定义,仍然可以通过实现来定义。如果MSDN是用MSVC编译器编写的,那么我就不会感到惊讶,在这种情况下,它可以很好地提供定义的行为。我相信GCC也会声明基于联合的类型惩罚。