繁体   English   中英

更好地理解extern“C”函数

[英]better understanding of extern “C” functions

我只是想进一步了解extern C函数。

根据我的知识,extern C函数始终是您正在尝试从已编译的应用程序调用的函数。 可执行文件,静态库或动态库。

extern "C" 
{
   HRESULT CreateDevice();
   typedef HRESULT (*CREATEDEVICE)();

   HRESULT ReleaseDevice();
   typedef HRESULT (*RELEASEDEVICE)();
}

所以我的问题是......

我的理解是否正确?

它总是必须是一个C函数指针??'

为什么必须为每个函数使用typedef?

我假设你使用GetProcAddress()。 您正在为特定应用程序HEAP分配内存,而不是您从中调用它的内存。 因此你必须从那个堆中释放它?

extern“C”有两个含义。 首先,它声明函数的符号名称不是“名称损坏”以支持C ++。 其次,它告诉编译器使用C调用约定而不是PASCAL调用约定调用该函数。 差异与在堆栈上推送返回地址的时间有关。 使用错误的调用约定会使您的应用程序崩溃。

此声明适用于编译器,而不是链接器。 因此extern C函数可以存在于您自己的模块或二进制库中:函数实现的实际字节源由链接器解析。 如果函数签名被声明为常规C ++函数而不是extern C,则编译器将破坏符号名称以编码函数签名中的类型信息。 这将使其与其他C ++编译器生成的目标代码不兼容。 因此,创建extern C函数允许您以二进制形式在编译器之间共享代码。 请注意,您不能以这种方式公开成员函数,只能使用旧式C函数。

它不必是函数指针。 您可以正常指定函数声明,并以extern "C"作为前缀,如某些Microsoft示例所示。

如果使用GetProcAddress() ,则不会分配任何内存。 您只需获取DLL中已加载到内存中的函数的内存地址LoadLibrary()可能是LoadLibrary() )。

即使使用函数指针(如由GetProcAddress的返回),你不必使用typedef ,它只是代码看起来没有它很丑陋。 总是很难弄清楚要写什么。 我想它会是这样的:

void (*pReleaseDevice)() = (void (__cdecl *)(void))GetProcAddress(hInstance, "ReleaseDevice");

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)()的别名,虽然我相信你必须把它放在函数之前(而不是之后)。

指定extern "C"链接的一个重要方面是函数名称不会被破坏,这是C ++名称的默认值。

为了能够使用GetProcAddress加载库的函数,您需要将函数添加到.def文件 ,使用__declspec(dllexport)或使用extern "C"

要按顺序回答:

  • extern“C”函数用于与C ++中的C互操作。 使用它们的结果是C代码可以调用该函数。 由于Windows API是一个C API,所有函数都是extern“C”,以确保C和C ++代码可以使用API​​。

  • 为了使c ++程序与其他语言(包括C)互操作作为约定,使用extern“C”导出函数。 这就是为什么很多DLL代码都会这样做的原因。 然而,这不是技术要求。

  • 所以不,它不一定是C函数指针。

  • 您也不必使用typedef。

提供的示例代码来自头文件,该头文件两次发布DLL的导出 - 一次作为导出的外部“C”方法的集合,以便dll可以静态链接。 另一个作为一组函数指针类型,这样dll可以动态加载,而函数指针类型与GetProcAddress一起使用。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM