更好地理解extern“C”函数

时间:2010-06-04 03:32:06

标签: c++ c visual-studio visual-studio-2008 visual-c++

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

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

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

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

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

我的理解是否正确?

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

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

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

5 个答案:

答案 0 :(得分:4)

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

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

答案 1 :(得分:1)

它不一定是函数指针。您可以正常指定函数声明,并在其前面添加extern "C",如some Microsoft examples所示。

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

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

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

答案 2 :(得分:0)

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

答案 3 :(得分:0)

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

为了能够使用GetProcAddress加载您的图书馆功能,您需要将功能添加到.def file,使用__declspec(dllexport)或使用extern "C"

答案 4 :(得分:0)

按顺序回答:

  • 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一起使用。