我一直在努力学习一些osx编程知识,以补充我的win32编程经验。我发现GetProcAddress的粗略等价物是dlsym。然后我遇到了一些意想不到的障碍。
我在查看旧论坛帖子和尝试的事情后,我的代码工作正常,但它与我的期望不符,也不符合我在Apple自己的文档中看到的。我希望有人能帮助我理解原因。
Apple documentation I was referring to
文档提供了一个如下所示的示例:
Person_creator* NewPerson = (Person_creator*)dlsym(lib_handle, "NewPerson");
我通过这样做得到了我的代码:
void (*printSome)() = (void(*)())dlsym(handle, "printSomething");
我认为我的代码应该这样做:
void* printSome = (void*)dlsym(handle, "printSomething");
然而,当我这样做并尝试调用printSome()时,我收到此错误消息:
Called object type 'void*' is not a function or function pointer
我有一个愚蠢的想法,它可能是一个无效函数指针的独特之处(即使我的经验没有提到它,我只是抓着试图理解)。
那么,是什么给出的?额外的语法是做什么的?为什么这在官方文档中没有出现?
答案 0 :(得分:2)
在C中,指向函数的指针的声明可能会令人困惑。 This website, “cdecl”,可以帮助您了解声明的含义。以下是它解释您的工作代码变量声明的方法:
输入:
的指针void (*printSome)()
输出:将printSome声明为函数返回void
以下是解码非工作代码变量声明的方法:
输入:
的指针void* printSome
输出:将printSome声明为void
请注意,第一个声明指向函数的指针,而第二个声明指向函数的指针。所以你不能在第二个上执行函数调用。
使用typedef
有助于简化声明,这就是Apple的文档使用typedef Person_creator
的原因。以下是如何使用typedef
代码。
首先,为与您要调用的函数具有相同签名的函数写出声明:
void PrintFunction(void);
然后将typedef
贴在前面:
typedef void PrintFunction(void);
请注意,我们已声明了 function 类型,而不是指向函数的指针类型。
现在你可以声明一个指向这种函数的指针,就像你声明一个指向非函数类型的指针一样:
PrintFunction *printSome;
由于dlsym
被声明为返回void *
,我们必须转换它的返回值。我们也可以使用typedef
:
PrintFunction *printSome = (PrintFunction *)dlsym(handle, "printSomething");
另请注意,C允许您直接对指向函数的指针执行函数调用,而无需解除引用。所以你可以这样称呼它:
printSome();
与明确解除引用效果相同:
(*printSome)();
由于您(在评论中)提到您正在观看Handmade Hero,我将解释Casey Muratori宣布函数类型的策略。让我们从第21天win32_handmade.cpp:175
开始考虑这个电话:
Result.UpdateAndRender = (game_update_and_render *)
GetProcAddress(Result.GameCodeDLL, "GameUpdateAndRender");
第{157}行UpdateAndRender
字段的声明如下:
game_update_and_render *UpdateAndRender;
所以Casey使用相同的typedef game_update_and_render
声明变量并转换GetProcAddress
的返回值。 (我猜Windows惯例是使用变量和函数的初始大写,以及类型的初始小写,这与Apple约定相反)。
typedef game_update_and_render
位于handmade.h:190
:
typedef GAME_UPDATE_AND_RENDER(game_update_and_render);
它使用前一行声明的GAME_UPDATE_AND_RENDER
宏:
#define GAME_UPDATE_AND_RENDER(name) void name(game_memory *Memory, game_input *Input, game_offscreen_buffer *Buffer)
最终,game_update_and_render
是函数类型的typedef
,就像Apple示例中的Person_creator
或上面的PrintFunction
一样。
为什么凯西使用GAME_UPDATE_AND_RENDER
宏?我想这是因为他可以使用相同的宏来定义该类型的实际功能,就像他在下一行(handmade.h:190
)上所做的那样:
GAME_UPDATE_AND_RENDER(GameUpdateAndRenderStub)
{
}
在这里,他定义了一个名为GameUpdateAndRenderStub
的函数,其签名(参数和返回类型)与typedef game_update_and_render
相同。没有宏,他必须重复参数并返回如下类型:
void GameUpdateAndRenderStub(game_memory *Memory, game_input *Input, game_offscreen_buffer *Buffer)
{
}