什么 *(DWORD_PTR*)&functionA = functionB( var1, var2);做?

What does *(DWORD_PTR*)&functionA = functionB( var1, var2); do?

*(DWORD_PTR*)&FunctionA =  FunctionB( var1, var2, etc...);

这段代码是什么意思?它有什么作用?

我尝试搜索 Google,但我不知道该使用什么术语。

之前的代码中有:

BOOL (WINAPI * FunctionA) (var1, var2, etc...) = NULL;

它标识了 "FunctionA" 是什么。

我假设是 *(DWORD_PTR*)&functionA 部分让您感到困惑?

让我们把它分解成几个部分。让我们从 &functionA 开始。它采用 functionA 的地址(无论是什么)和 return 指向它的指针。

然后我们有 (DWORD_PTR*) 将指向 functionA 的指针转换为指向 DWORD_PTR 的指针。

最后是开头唯一的 *,它是解引用运算符,它接受一个指针并为您提供 if 指向的值。

和函数调用放在一起,就是简单的把调用functionB的结果赋值给变量functionA.

我只是在猜测,但有可能 functionB return 是一个以某种通用方式指向函数的指针(因为 DWORD_PTR 是我的猜测)然后将其分配给变量 functionA ,该变量可能具有指向函数的类型指针。转换和寻址和取消引用运算符是因为 return 类型 functionB我猜。没有更多信息或上下文,就无法确定。

这是丑陋的代码,就是这样。

基本上所做的是调用一个函数 (FunctionB),该函数 return 是指向另一个函数的指针,并将该指针分配给变量 FunctionA。现在,如果仅此而已,那么代码将看起来非常简单:

FunctionA = FunctionB( var1, var2, etc... );

不幸的是,由于某些奇怪的原因(这可能对最初设计 API 的人来说很有意义),FunctionB 的 return 类型是 not 声明为函数指针,而是 DWORD_PTR(与底层平台上的指针大小匹配的整数类型)。这意味着 FunctionB 的 return 值不能直接分配给变量 FunctionA,而必须首先转换为实际的函数指针(正如注释中所指出的那样, 根据 C 标准在技术上是未定义的行为,尽管 POSIX 确实为它定义了语义)。

现在,如果 FunctionA 变量的类型很简单,比如 my_func_ptr_t,那么这仍然很容易写:

FunctionA = (my_func_ptr_t) FunctionB( var1, var2, etc... );

但是,唉,在你的代码中 FunctionA 声明为:

BOOL (WINAPI * FunctionA) (arg1, arg2, etc...) = NULL;

这意味着它的类型类似于 BOOL (WINAPI *) (arg1, arg2, etc...),因此转换看起来像这样:

FunctionA = (BOOL (WINAPI *) (arg1, arg2, etc...)) FunctionB( var1, var2, etc... );

似乎编写该代码的人认为这样的转换太复杂了,而是想出了一个技巧:不是将 FunctionB 的 return 值转换为函数指针,像这样将 FunctionA 转换为 DWORD_PTR 不是更容易吗:

(DWORD_PTR) FunctionA = FunctionB( var1, var2, etc... ); /* this doesn't work :( */

当然,那不会编译;强制转换只是将变量的 value 转换为另一种类型,您不能为转换后的值赋值。 (在技术术语中,a cast is not an lvalue.)但是等等,您 可以 分配给取消引用的指针!所以如果我们...

  1. 获取指向 FunctionA 的指针(因此将是指向函数指针的指针),
  2. 将其转换为指向 DWORD_PTR 的指针,并且
  3. 取消引用该指针,

然后我们得到一个有效的 DWORD_PTR 左值,我们可以分配给它,它恰好与变量 FunctionA 共享相同的内存地址。没关系,根据 C 标准,所有这一切都会以六种方式调用未定义的行为——我们知道我们的编译器会按照我们期望的方式处理它,对吗?

所以,这正是代码的作用:

  1. &FunctionA returns 指向变量的指针 FunctionA,
  2. (DWORD_PTR *) 转换此指针,使其现在声称指向 DWORD_PTR 类型的变量,并且
  3. 左侧的 * 取消引用此指针,因此 FunctionB 的 return 值被分配给它指向的任何内存位置(方便地,恰好是 FunctionA).
  4. 的位置

但是,当然,所有这一切都依赖于(非标准)假设,即在特定的编译器和平台上,此代码的目的是将 DWORD_PTR 写入内存,然后使用相同的内存位置作为函数指针实际工作并调用预期函数,而不是触发访问冲突、跳转到错误地址或 making demons fly out of your nose.


好的,这是丑陋的代码。那我该怎么做比较好呢?

好吧,理想情况下,我会更改 FunctionB 以便它实际上 return 一个适当类型的函数指针,这样就需要 none 这些转换恶作剧首先。

如果由于某种原因这真的不可能(我会非常努力地 使 成为可能,甚至在必要时重新设计 API,下一个最佳解决方案是显式转换 FunctionB 的 return 值。当然,这是未定义的行为,但至少它明确说明了它试图做什么。

无论哪种方式,我肯定会 typedef 将实际的函数指针类型转换为更具可读性的类型。这样,代码(带有显式转换)可能最终看起来像这样:

typedef BOOL (WINAPI * my_func_ptr_t) (arg1, arg2, etc...);
my_func_ptr_t FunctionA = NULL;
/* ... */
FunctionA = (my_func_ptr_t) FunctionB( var1, var2, etc... );