虚空**的含义是什么?

smw*_*dia 11 c c# c++ com

当我在COM中开发时,我总是看到(void**)类型转换如下.

QueryInterface(/* [in] */ REFIID riid,/* [out] */ void** ppInterface)
Run Code Online (Sandbox Code Playgroud)

它的确切含义是什么?

恕我直言,它告诉编译器不要强制执行类型验证,因为在编译时客户端代码不知道ppInterface指向的类型.

谢谢~~~

更新1

我这样理解:

void*p表示 AnyType*p

void**pp 表示指向AnyType的指针*

更新2

如果void**pp表示"指向void*的指针",那么编译器在看到它时会做什么检查?

sta*_*ica 18

为什么COM使用的原因void**QueryInterface是有点特殊.(见下文.)

通常, void**简单地表示指向void*,并且它可以用于输出参数,即.指示函数可以返回值的位置的参数.您的注释/* [out] */表示ppvInterface将写入指向的位置.

"为什么带有指针类型的参数可以用作输出参数?" , 你问?请记住,您可以使用指针变量更改两件事:

  1. 您可以更改指针本身,使其指向另一个对象.(ptr = ...)
  2. 您可以修改指向的对象.(*ptr = ...)

指针按值传递给函数,即.该函数获取自己传递给它的原始指针的本地副本.这意味着您可以更改函数(1)中的指针参数,而不会影响原始指针,因为只修改了本地副本.但是,您可以更改指向对象(2),这将在函数外部可见,因为副本具有与原始指针相同的值,因此引用相同的对象.

现在,关于COM具体:

  • 指向接口(由指定者riid)的指针将在引用的变量中返回ppvInterface.QueryInterface通过上述机制(2)实现这一点.

  • void**,*需要一个机制(2); 另一个*反映了这样的事实:QueryInterface不返回新创建的对象(IUnknown),而是已经存在的对象:为了避免重复该对象,IUnknown*返回指向该对象()的指针.

  • 如果你问为什么ppvInterface有类型void**而不是IUnknown**,这似乎更合理的类型安全性(因为所有接口必须来自IUnknown),然后阅读下面的参数取自Don Box 的书Essential COM,p.60(章节类型强制和IUnknown):


另一个与细节相关的细微QueryInterface问题涉及其第二个参数,即类型void **.具有讽刺意味的是QueryInterface,COM类型系统的基础在C++中具有相当类型不安全的原型[...]

 IPug *pPug = 0;
 hr = punk->QueryInterface(IID_IPug, (void**)&pPug);
Run Code Online (Sandbox Code Playgroud)

不幸的是,以下内容对C++编译器来说同样正确:

 IPug *pPug = 0;
 hr = punk->QueryInterface(IID_ICat, (void**)&pPug);
Run Code Online (Sandbox Code Playgroud)

这种更微妙的变化也可以正确编译:

 IPug *pPug = 0;
 hr = punk->QueryInterface(IID_ICat, (void**)pPug);
Run Code Online (Sandbox Code Playgroud)

鉴于继承规则不适用于指针,这种替代定义QueryInterface并不能解决问题:

 HRESULT QueryInterface(REFIID riid, IUnknown** ppv);
Run Code Online (Sandbox Code Playgroud)

同样的限制也适用于指针的引用.对于客户来说,以下替代定义可以更方便地使用:

 HRESULT QueryInterface(const IID& riid, void* ppv);
Run Code Online (Sandbox Code Playgroud)

[...]不幸的是,这个解决方案并没有减少错误的数量,并且通过消除对转换的需要,删除了C++类型安全可能处于危险中的可视指示符.鉴于所需的语义QueryInterface,微软选择的参数类型是合理的,如果不是类型安全或优雅.[...]


caf*_*caf 17

A void **是指向a的指针void *.这可以用于传递void *将用作输出参数的变量的地址- 例如:

void alloc_two(int n, void **a, void **b)
{
    *a = malloc(n * 100);
    *b = malloc(n * 200);
}

/* ... */

void *x;
void *y;

alloc_two(10, &x, &y);
Run Code Online (Sandbox Code Playgroud)

  • 很好的例子:) +1 (2认同)

lep*_*pie 5

它只是一个指针void*.

例如:

Something* foo;
Bar((void**)&foo);

// now foo points to something meaningful
Run Code Online (Sandbox Code Playgroud)

编辑: C#中可能的实现.

  struct Foo { }

  static Foo foo = new Foo();

  unsafe static void Main(string[] args)
  {
    Foo* foo;

    Bar((void**)&foo);
  }

  static unsafe void Bar(void** v)
  {
    fixed (Foo* f = &foo)
    {
      *v = f;
    }
  }
Run Code Online (Sandbox Code Playgroud)

  • @leppie:C可能只是"开心",因为许多C编译器仅仅因为这样的情况而将自己限制为"警告".尽管如此,即使在C中,这也是违反约束(即"错误"). (2认同)