*(DWORD_PTR*)&FunctionA = FunctionB( var1, var2, etc...);
这段代码是什么意思?它做了什么?
我试图搜索Google,但我不知道要使用哪些条款。
以前在代码中有:
BOOL (WINAPI * FunctionA) (var1, var2, etc...) = NULL;
标识“FunctionA”是什么。
答案 0 :(得分:3)
我认为*(DWORD_PTR*)&functionA
部分让你感到困惑?
让我们把它分解成几部分。让我们从&functionA
开始。它接受functionA
的地址(无论是什么)并返回指向它的指针。
然后我们有(DWORD_PTR*)
将指向functionA
的指针转换为指向DWORD_PTR
的指针。
最后是开头的唯一*
,它是取消引用运算符,它接受一个指针,并为您提供if指向的值。
与函数调用放在一起,它只是将调用functionB
的结果赋给变量functionA
。
我只是在这里猜测,但functionB
可能以某种通用的方式返回指向函数的指针(因为DWORD_PTR
将是我的猜测),然后将其赋给变量{ {1}}可能有函数的类型指针。 cast和address-of和dereference运算符是因为functionA
的返回类型。 我猜 。没有更多信息或背景,就无法确定任何事情。
答案 1 :(得分:1)
这是丑陋的代码,就是这样。
基本做的是调用一个函数(FunctionB
),该函数返回指向另一个函数的指针,并将该指针赋给变量FunctionA
。现在,如果这就是全部,那么代码看起来很简单:
FunctionA = FunctionB( var1, var2, etc... );
不幸的是,出于一些奇怪的原因(可能对最初设计该API的人来说很有意义),FunctionB
的返回类型是而不是被声明为函数指针,而是DWORD_PTR
(一种与底层平台上指针大小相匹配的整数类型)。这意味着FunctionB
的返回值不能直接分配给变量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
的返回值转换为函数指针,不是这样的更容易将FunctionA
投射到DWORD_PTR
中,如下所示:
(DWORD_PTR) FunctionA = FunctionB( var1, var2, etc... ); /* this doesn't work :( */
但当然,这不会编译;强制转换只是将变量的值转换为另一种类型,并且您无法为转换后的值赋值。 (在技术术语中,a cast is not an lvalue.)但是等等,你可以分配给一个解除引用的指针!所以,如果我们......
FunctionA
的指针(因此将是指向函数指针的指针),DWORD_PTR
和然后我们得到一个有效的DWORD_PTR
左值,我们可以分配给它,它恰好与变量FunctionA
共享相同的内存地址。根本不需要考虑所有这些根据C标准调用未定义的行为六种方式 - 我们知道我们的编译器会以我们期望的方式处理它,对吗?
所以,这正是代码的作用:
&FunctionA
返回指向变量FunctionA
,(DWORD_PTR *)
强制转换此指针,以便它现在声称指向DWORD_PTR
类型的变量,并且*
取消引用此指针,以便将FunctionB
的返回值分配给它指向的任何内存位置(方便地,它恰好是{{的位置) 1}})。但是,当然,所有这些都依赖于(非标准)假设,在这个代码的特定编译器和平台上,将FunctionA
写入内存然后使用相同的内存位置作为函数指针实际上工作并调用预期的函数,而不是例如触发访问冲突,跳转到错误的地址,或making demons fly out of your nose.
好的,所以这是丑陋的代码。那我怎么能做得更好呢?
嗯,理想情况下,我会更改DWORD_PTR
,以便它实际返回一个相应类型的函数指针,这样就不会首先需要这些投射恶作剧。
如果由于某种原因真的不可能(并且我很努力使成为可能,甚至在必要时重新设计API),下一个最佳解决方案是明确地投射返回值FunctionB
。当然,它是未定义的行为,但至少它明确地说明了它想要做什么。
无论哪种方式,我绝对会FunctionB
将实际的函数指针类型转换为更具可读性的东西。这样,代码(带有显式强制转换)最终可能看起来像这样:
typedef