我一直在尝试获取一些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
我愚蠢地认为这可能是void函数指针所特有的(尽管根据我的经验,它什么也没有暗示,但我只是在试图理解)。
那么,有什么用呢?额外的语法在做什么?为什么在官方文档中什么也没有出现?
最佳答案
在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);
请注意,我们已经声明了一个函数类型,而不是一个指向函数的指针。
现在,您可以声明指向此类函数的指针,就像声明非函数类型的指针一样:
PrintFunction *printSome;
由于声明
dlsym
返回void *
,因此我们必须转换其返回值。我们也可以在那里使用typedef
:PrintFunction *printSome = (PrintFunction *)dlsym(handle, "printSomething");
还要注意,C允许您直接对指向函数的指针执行函数调用,而无需取消引用。因此,您可以这样称呼它:
printSome();
与显式取消引用具有相同的作用:
(*printSome)();
更新
由于您提到(在评论中)您正在观看,因此,我将解释Casey Muratori声明函数类型的策略。让我们考虑从第21天起在
win32_handmade.cpp:175
处进行的调用:Result.UpdateAndRender = (game_update_and_render *)
GetProcAddress(Result.GameCodeDLL, "GameUpdateAndRender");
UpdateAndRender
字段在第157行中声明为: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
一样。Casey为什么使用
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)
{
}
关于c++ - 试图了解dlsym的语法怪异,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/45180020/