更好地理解外部“C”函数
Posted
技术标签:
【中文标题】更好地理解外部“C”函数【英文标题】:better understanding of extern "C" functions 【发布时间】:2010-06-04 03:32:05 【问题描述】:我只是想进一步了解外部 C 函数。
据我所知,extern C 函数始终是您尝试从已编译的应用程序调用的函数。可执行、静态或动态库。
extern "C"
HRESULT CreateDevice();
typedef HRESULT (*CREATEDEVICE)();
HRESULT ReleaseDevice();
typedef HRESULT (*RELEASEDEVICE)();
所以我的问题是......
我的理解正确吗??
它总是必须是一个 C 函数指针吗??'
为什么必须为每个函数使用 typedef ??
我认为当您使用 GetProcAddress() 时。您正在该特定应用程序 HEAP 上分配内存,而不是您从中调用它的应用程序。因此,您也必须从该堆中释放它??
【问题讨论】:
你看到这个问题了吗? ***.com/questions/67894/… 【参考方案1】:extern "C" 有两个含义。首先,它声明函数的符号名称不是“名称混乱”以支持 C++。其次,它告诉编译器该函数是使用 C 调用约定而不是 PASCAL 调用约定调用的。差异与返回地址何时被压入堆栈有关。使用错误的调用约定会导致您的应用崩溃。
此声明适用于编译器,而不是链接器。因此,extern C 函数可以存在于您自己的模块或二进制库中:函数实现的实际字节源由链接器解析。如果函数签名被声明为常规 C++ 函数而不是外部 C,编译器将修改符号名称以对函数签名中的类型信息进行编码。这将使其与其他 C++ 编译器生成的目标代码不兼容。因此,创建 extern C 函数允许您在编译器之间以二进制形式共享代码。请注意,您不能以这种方式公开成员函数,只能公开旧式 C 函数。
【讨论】:
【参考方案2】:它不一定是函数指针。可以正常指定函数声明,前缀extern "C"
,如some Microsoft examples所示。
如果您使用GetProcAddress()
,则不会分配任何内存。您只需获取DLL中已经加载到内存中的函数的内存地址(大概是LoadLibrary()
)。
即使在使用函数指针(例如由 GetProcAddress 返回的指针)时,您也没有有使用typedef
,只是没有它,代码看起来很丑。总是很难弄清楚该写什么。我想应该是这样的:
void (*pReleaseDevice)() = (void (__cdecl *)(void))GetProcAddress(hInstance, "ReleaseDevice");
【讨论】:
请注意,__cdecl 是 Microsoft 特定的。 @Billy ONeal:GetProcAddress
和 Visual Studio 也是如此。
GetProcAddress 不是 Microsoft 特定的,而是 Windows 特定的。例如,我可以将 GetProcAddress 与 MinGW 一起使用,但不能使用 __cdecl。
为了记录我 +1 的记录,我只是认为这是一个重要的说明。【参考方案3】:
extern "C" 是一种 C++ 约定,用于声明所包含的函数是 C 函数,而不是 C++ 函数。 C++ 有一个稍微不同的命名约定,它与 C 冲突。如果你有一个用 C 编写的库并想在 C++ 程序中使用它,你必须使用 extern "C" 让编译器知道这些是 C 函数。如果库是用 C++ 编写的,我相信 extern "C" 会导致错误。
请注意,extern 有多种含义——这种特殊情况是 C++ 约定,与 extern 的不同用途无关。例如,
extern int count;
与 extern "C" 的含义完全不同。
typedef 与 extern "C" 问题是分开的。 typedefs 允许您为更有意义的常见类型创建别名。例如,声明结构通常是一个冗长的过程。我可以使用 typedef 来缩短它:
struct mystruct int a; int b;
typedef struct mystruct returncode;
// I can now declare a variable as type 'returncode'
returncode a;
因此,在您的示例中,HRESULT 实际上是 (*CREATEDEVICE)() 的别名,尽管我相信您必须将它放在函数之前(而不是之后)。
【讨论】:
【参考方案4】:指定extern "C"
链接的一个重要方面是函数名称不会被破坏,这是 C++ 名称的默认设置。
为了能够使用GetProcAddress
加载库的函数,您需要将函数添加到.def file、使用__declspec(dllexport)
或使用extern "C"
。
【讨论】:
【参考方案5】:按顺序回答:
extern "C" 函数用于与 C++ 中的 C 进行互操作。使用它们的结果是 C 代码可以调用该函数。由于 windows API 是 C API,所有函数都是外部“C”,以确保 C 和 C++ 代码可以使用该 API。
为了让 c++ 程序与其他语言(包括 C)互操作,按照惯例,使用 extern "C" 导出函数。这就是为什么很多 dll 代码都这样做的原因。然而,这不是技术要求。
所以不,它不一定是 C 函数指针。
您也不必使用 typedef。提供的示例代码来自一个头文件,该文件两次发布 DLL 的导出 - 一次作为导出的一组外部“C”方法,以便可以静态链接 dll。另一种为一组函数指针类型,使dll可以动态加载,函数指针类型与GetProcAddress配合使用。
【讨论】:
以上是关于更好地理解外部“C”函数的主要内容,如果未能解决你的问题,请参考以下文章