难以理解沿函数指针的 typedef
Trouble understanding a typedef along function pointers
即使在此处阅读了有关此主题的一些答案之后,我仍然很难理解以下语法的确切作用:
typedef BOOL (WINAPI *DllEntryProc)(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved);
我的猜测:
它将 DllEntryProc
数据类型定义为 BOOL
的别名,其中 DllEntryProc
是指向函数的指针,该函数接受一个 HINSTANCE
、一个 DWORD
和一个 LPVOID
作为参数和 returns a WINAPI
?
上面的代码是关于如何从内存加载 DLL 的 this article 的一部分。然后像这样调用该函数:
DllEntryProc entry = (DllEntryProc) someValue;
(*entry)((HINSTANCE)baseAddress, DLL_PROCESS_ATTACH, 0);
返回一个 BOOL
(感谢那个 typedef),对吗?
它将DllEntryProc
数据类型定义为BOOL的别名,其中DllEntryProc是一个指向函数的指针,该函数采用一个HINSTANCE、一个DWORD和一个LPVOID作为参数和 returns 一个 WINAPI BOOL
typedef BOOL (WINAPI *DllEntryProc)(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved);
DllEntryProc
是一种类似于 int
的新类型,您可以像声明 int
.
类型的变量一样声明此类型的变量
DllEntryProc somevar;
现在,您可以分配给 somevar
的值应该是 DllEntryProc
类型,它是指向所述类型的函数的指针。
当 typedef 用于函数指针时,您可以给它一个 友好的名称,这样可以更轻松地使用该定义创建和引用指针。例子
#include<stdio.h>
int test(int a, char b, float c){
printf("a=%d,b=%c,c=%f\n",a,b,c);
}
typedef int (*test_p)(int a, char b, float c);
int main(){
test_p ptr = test;
ptr(10, 'a', 5.5);
}
# gcc test.c
# ./a.out
a=10,b=a,c=5.500000
回到你的函数指针声明。
typedef BOOL (WINAPI *DllEntryProc)(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved);
等同于:
typedef int (*test_p)(int a, char b, float c);
此处 WINAPI 是一个计算结果为 __stdcall 的宏,它是 Microsoft 特定的关键字,指定被调用方清理堆栈的调用约定。函数的调用者和被调用者需要就调用约定达成一致以避免破坏堆栈。
typedef
创建函数指针类型。简而言之,函数指针是这样工作的:
给定一个函数 void func (void)
,声明一个指向该函数的函数指针 void (*ptr) (void)
。同一个函数指针的 typedef
可以写成:
typedef void (*ptr_t) (void);
,用法 ptr_t ptr;
,或
typedef void ptr_t (void);
,用法ptr_t* ptr
。
前一种风格可能是最常见的,也是 Windows API 使用的风格。我个人觉得后一种风格更清晰,因为它与对象指针一致,但这只是一个偏好问题 - 两者都可以。
函数指针现在可用于通过 ptr()
或 (*ptr)()
调用函数 - 它们是等效的,只是样式不同。
详细剖析typedef BOOL (WINAPI *DllEntryProc)(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved);
:
BOOL
是 Windows API 风格的布尔类型。 Windows API 早于 C99,因此他们使用自定义布尔类型。
WINAPI
是一个宏,它隐藏了指定函数使用的 calling convention 的非标准语法。它扩展为 __stdcall
。简而言之,调用约定是调用者或被调用者负责堆叠参数。
在与 DLL:s 通信时,使用正确的调用约定非常重要,因为 DLL:s 与语言无关,各种编程语言使用不同的调用约定。 C 和 C++ 倾向于默认使用 __cdecl
调用约定(参见 link),因此在重要的情况下需要指定不同的调用约定,例如 DLL:s.
DllEntryProc
是函数指针类型的新名称。
HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved
是函数参数。在 typedef 期间使用参数名称是可选的(但很好的做法)。
至于这个类型的作用,它创建了一个指向DLL中存在的DllMain/DllEntryPoint函数(不同名称相同含义)的函数指针。每个 DLL 都有这样一个函数,它是某种“构造函数”,在加载 DLL 时调用。从头开始编写您自己的 DLL:s 代码时,您必须提供此函数(但是有很多关于您不应该在 DllMain 中执行的操作的规则)。
通常,在使用 DLL 的应用程序中,每个 DLL 函数都有一个函数指针是常见的做法,因为用于从 DLL 获取函数的 GetProcAddress
只是 returns通用函数指针。
(*entry)((HINSTANCE)baseAddress, DLL_PROCESS_ATTACH, 0);
是对 DllMain/DllEntryPoint 的显式函数调用。由于它是一个函数指针,替代但等效的语法是:
entry((HINSTANCE)baseAddress, DLL_PROCESS_ATTACH, 0);
这可能是更清晰的样式,因为它看起来就像一个函数调用。
即使在此处阅读了有关此主题的一些答案之后,我仍然很难理解以下语法的确切作用:
typedef BOOL (WINAPI *DllEntryProc)(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved);
我的猜测:
它将 DllEntryProc
数据类型定义为 BOOL
的别名,其中 DllEntryProc
是指向函数的指针,该函数接受一个 HINSTANCE
、一个 DWORD
和一个 LPVOID
作为参数和 returns a WINAPI
?
上面的代码是关于如何从内存加载 DLL 的 this article 的一部分。然后像这样调用该函数:
DllEntryProc entry = (DllEntryProc) someValue;
(*entry)((HINSTANCE)baseAddress, DLL_PROCESS_ATTACH, 0);
返回一个 BOOL
(感谢那个 typedef),对吗?
它将DllEntryProc
数据类型定义为BOOL的别名,其中DllEntryProc是一个指向函数的指针,该函数采用一个HINSTANCE、一个DWORD和一个LPVOID作为参数和 returns 一个 WINAPI BOOL
typedef BOOL (WINAPI *DllEntryProc)(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved);
DllEntryProc
是一种类似于 int
的新类型,您可以像声明 int
.
DllEntryProc somevar;
现在,您可以分配给 somevar
的值应该是 DllEntryProc
类型,它是指向所述类型的函数的指针。
当 typedef 用于函数指针时,您可以给它一个 友好的名称,这样可以更轻松地使用该定义创建和引用指针。例子
#include<stdio.h> int test(int a, char b, float c){ printf("a=%d,b=%c,c=%f\n",a,b,c); } typedef int (*test_p)(int a, char b, float c); int main(){ test_p ptr = test; ptr(10, 'a', 5.5); } # gcc test.c # ./a.out a=10,b=a,c=5.500000
回到你的函数指针声明。
typedef BOOL (WINAPI *DllEntryProc)(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved);
等同于:
typedef int (*test_p)(int a, char b, float c);
此处 WINAPI 是一个计算结果为 __stdcall 的宏,它是 Microsoft 特定的关键字,指定被调用方清理堆栈的调用约定。函数的调用者和被调用者需要就调用约定达成一致以避免破坏堆栈。
typedef
创建函数指针类型。简而言之,函数指针是这样工作的:
给定一个函数 void func (void)
,声明一个指向该函数的函数指针 void (*ptr) (void)
。同一个函数指针的 typedef
可以写成:
typedef void (*ptr_t) (void);
,用法ptr_t ptr;
,或typedef void ptr_t (void);
,用法ptr_t* ptr
。
前一种风格可能是最常见的,也是 Windows API 使用的风格。我个人觉得后一种风格更清晰,因为它与对象指针一致,但这只是一个偏好问题 - 两者都可以。
函数指针现在可用于通过 ptr()
或 (*ptr)()
调用函数 - 它们是等效的,只是样式不同。
详细剖析typedef BOOL (WINAPI *DllEntryProc)(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved);
:
BOOL
是 Windows API 风格的布尔类型。 Windows API 早于 C99,因此他们使用自定义布尔类型。WINAPI
是一个宏,它隐藏了指定函数使用的 calling convention 的非标准语法。它扩展为__stdcall
。简而言之,调用约定是调用者或被调用者负责堆叠参数。在与 DLL:s 通信时,使用正确的调用约定非常重要,因为 DLL:s 与语言无关,各种编程语言使用不同的调用约定。 C 和 C++ 倾向于默认使用
__cdecl
调用约定(参见 link),因此在重要的情况下需要指定不同的调用约定,例如 DLL:s.DllEntryProc
是函数指针类型的新名称。HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved
是函数参数。在 typedef 期间使用参数名称是可选的(但很好的做法)。
至于这个类型的作用,它创建了一个指向DLL中存在的DllMain/DllEntryPoint函数(不同名称相同含义)的函数指针。每个 DLL 都有这样一个函数,它是某种“构造函数”,在加载 DLL 时调用。从头开始编写您自己的 DLL:s 代码时,您必须提供此函数(但是有很多关于您不应该在 DllMain 中执行的操作的规则)。
通常,在使用 DLL 的应用程序中,每个 DLL 函数都有一个函数指针是常见的做法,因为用于从 DLL 获取函数的 GetProcAddress
只是 returns通用函数指针。
(*entry)((HINSTANCE)baseAddress, DLL_PROCESS_ATTACH, 0);
是对 DllMain/DllEntryPoint 的显式函数调用。由于它是一个函数指针,替代但等效的语法是:
entry((HINSTANCE)baseAddress, DLL_PROCESS_ATTACH, 0);
这可能是更清晰的样式,因为它看起来就像一个函数调用。