试图理解围绕 dlsym 的语法怪癖
Trying to understand syntax quirk around dlsym
我一直在尝试学习一些osx编程知识来补充我的win32编程经验。我发现GetProcAddress的粗略等价物是dlsym。然后我遇到了一些意想不到的障碍。
在检查旧的论坛帖子和尝试一些东西之后,我的代码得到了工作,但它不符合我的期望,也不符合我在 Apple 自己的文档中看到的内容。我希望这里有人可以帮助我理解为什么。
我所指的苹果文档
该文档提供了一个如下所示的示例:
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
我有一个愚蠢的想法,它可能是空函数指针所独有的东西(尽管我的经验中没有任何迹象表明它会是这样,我只是在试图理解(。
那么,什么给了呢?额外的语法在做什么?为什么这在官方文档中没有出现?
在 C 中,指向函数的指针的声明可能会令人困惑。本网站"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
一样。
为什么凯西使用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)
{
}
- 1d 智能指针不适用于语法 (*)++
- 助记符和指向成员语法的指针
- 有人能分解一下这个c++模板的语法吗
- C++避免重复声明的语法是什么
- QMetaObject invokeMethod的基于函数指针的语法
- 这个语法std::class<>{}(arg1, arg2) 在C++中是什么意思?
- 为什么包含windows.h会产生语法错误,从而阻止类的实例化?(C2146,C2065)
- 单独定义模板化嵌套类方法的正确语法
- 共享指针和具有自定义删除程序的唯一指针之间的语法差异背后的任何原因
- 错误 C2760:语法错误:映射迭代器上意外的标记"标识符",预期的";"
- 为什么我会收到错误 C2143 语法错误:缺少"*"之前的';'?
- 奇怪的代码抛出编译错误模板< J,int aSize=10> C2143:语法错误:在"<"之前缺少";"
- 使用基类指针调用基类的值构造函数的语法是什么?
- 很好的语法来获取对向量/数组数据的大小引用?
- C++语法运算符功能?
- C++使用 rand 定义函数语法
- 什么文件可以修改 atom 的C++语法?
- 创建模板嵌套类实例的语法?
- C++语法差异:二维和一维数组(指针算术)
- 试图理解围绕 dlsym 的语法怪癖