VARIANT 类型 punkVal 给出未定义的值?
我使用一些 CComVariant 类型变量来存储接口指针。但是,有时我需要将接口指针作为 NULL 传递。在这种情况下,当我这样做时:
CComVariant vAData,vBData;
......
....
CComQIPtr<IBData> pAData = vAData.punkVal; //vAData is {0, VT_I4} when I pass NULL
CComQIPtr<IBData>pBData = vBData.punkVal; //vBData is {0, VT_I4} when I pass NULL
第一行失败并抛出异常,因为 vAData.punkVal = 0xffffffff00000000< /代码> 但第二行运行良好,没有错误,并且具有有效的 vBData.punkVal 值 (0x0000000000000000)。
我想知道为什么两个 punkVal 都为 NULL 时不同? 有人知道为什么会发生这种情况吗? 这仅在 64 位机器上引发异常。
I am using few CComVariant type variables to store interface pointers.However, sometime I need to pass interface pointer as NULL.In this case when I do this:
CComVariant vAData,vBData;
......
....
CComQIPtr<IBData> pAData = vAData.punkVal; //vAData is {0, VT_I4} when I pass NULL
CComQIPtr<IBData>pBData = vBData.punkVal; //vBData is {0, VT_I4} when I pass NULL
The first line fails and throws exception since the vAData.punkVal = 0xffffffff00000000
But the second line passes fine with no error and it has valid vBData.punkVal
value(0x0000000000000000).
I am wondering why the two punkVal are different when both are NULL??
Does anybody has any idea why this is happening??
This throws exception only on 64bit machines.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
关于 VARIANT 的一些附加信息:它们有点奇怪,因为它们是复合类型:它基本上是几种类型的联合,每种类型的字段(bstrVal、lVal、punkVal 等)都占用内存中的相同空间,并且vt 字段指示哪个字段有效。
您应该只尝试访问与 vt 值匹配的字段。所以如果vt是VT_BSTR,那么只有bstrVal有效;朋克瓦尔是禁区。如果 vt 是 VT_I4,则仅应使用 lVal 字段。
VT_EMPTY 表示“此变量尚未设置为任何值,因此不代表任何内容”;当 vt 为 VT_EMPTY 时,所有字段都是禁止的 - 它们可能是之前堆栈上恰好出现的任何垃圾 - 这就是您在这里看到的。
在Win64中,整数仍然是32位,但指针是64位。 VT_I4 类型且值为 0 的变体将表示整数的 32 位全部设置为 0,但变体中的其余内存可能是任何剩余的垃圾。如果您尝试将该内存视为 64 位指针 - 通过访问 punkVal - 那么您最终会得到一个由这 32 个 0 位组成的指针,而且还来自从未正确初始化的相邻 32 位 - 这可能就是原因您在这里看到了两种情况之间的差异。
在 Win32 中,你很幸运:指针的大小与 int 相同,因此如果你访问 0 的 VT_I4 并读取 punkVal(你不应该这样做!),在这种情况下你最终会得到一个 NULL 指针。
Some additional information about VARIANTs: they're somewhat weird in that they are compound types: it's basically a union of several types, with the fields for each type (bstrVal, lVal, punkVal, etc) all occupying the same space in memory, and the vt field indicating which field is valid.
You should only attempt to access the field that matches the value of vt. So if vt is VT_BSTR, then only bstrVal is valid; punkVal is off-limits. If vt is VT_I4, then only the lVal field should be used.
VT_EMPTY means "this variant hasn't been set to any value, so doesn't represent anything"; when vt is VT_EMPTY, all fields are off-limits - they might be whatever garbage just happened to be on the stack before - which is what you are seeing here.
In Win64, integers are still 32-bits, but pointers are 64 bits. A variant that is of type VT_I4 with value 0 will have the 32 bits that represent the integer all set to 0, but the rest of the memory in the variant could be any leftover garbage. If you try to treat that memory as a 64-bit pointer - by accessing punkVal - then you'll end up with a pointer made from those 32 0 bits, but also from an adjacent 32bits that have never been properly initialized - that's likely why you're seeing differences between the two cases here.
In Win32, you get lucky: the pointer is the same size as the int, so if you access a VT_I4 that's 0 and read the punkVal (which you shouldn't!), you would end up getting a NULL pointer in that case.
CComVariant
在构造函数中调用VariantInit()
,并将vt
设置为VT_EMPTY
,但留下punkVal
code> 未初始化(不会使其为空)。因此,您尝试做的是未定义的行为,因为您尝试构造一个
CComQIPtr
并将其传递给一个未初始化的指针。如果您想要一个
CComVariant
持有 nullIUnknown*
,您可以这样做:现在构造一个
CComQIPtr
是完全合法的:CComVariant
callsVariantInit()
in constructor and that setsvt
toVT_EMPTY
, but leavespunkVal
uninitialized (doesn't make it null).What you try to do is therefore undefined behavior since you try to construct a
CComQIPtr
passing it an uninitialized pointer.If you want a
CComVariant
holding a nullIUnknown*
you can do this:now it's perfectly legal to construct a
CComQIPtr
: