简体   繁体   English

更好地理解extern“C”函数

[英]better understanding of extern “C” functions

I am just trying to further understand extern C functions. 我只是想进一步了解extern C函数。

According to my knowledge, an extern C function is always a function you are trying call from an application that has already been compiled. 根据我的知识,extern C函数始终是您正在尝试从已编译的应用程序调用的函数。 Either a executable, static or dynamic library. 可执行文件,静态库或动态库。

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

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

So my question is... 所以我的问题是......

Is my understanding correct ?? 我的理解是否正确?

Does it always have to be a C function pointer ??' 它总是必须是一个C函数指针??'

Why must you use a typedef for each function ?? 为什么必须为每个函数使用typedef?

I presume that when you use the GetProcAddress(). 我假设你使用GetProcAddress()。 You are allocating memory on that particulars applications HEAP and not the one you are calling it from. 您正在为特定应用程序HEAP分配内存,而不是您从中调用它的内存。 Therefore you must release it from that heap as well ?? 因此你必须从那个堆中释放它?

extern "C" has 2 implications. extern“C”有两个含义。 First, it declares that the symbolic names of the functions are not "name mangled" to support C++. 首先,它声明函数的符号名称不是“名称损坏”以支持C ++。 Second, it tells the compiler that the function is called using the C calling convention rather than the PASCAL calling convention. 其次,它告诉编译器使用C调用约定而不是PASCAL调用约定调用该函数。 The difference has to do with when the return address is pushed on the stack. 差异与在堆栈上推送返回地址的时间有关。 Using the wrong calling convention will crash your app. 使用错误的调用约定会使您的应用程序崩溃。

This declaration is for the compiler, not the linker. 此声明适用于编译器,而不是链接器。 So the extern C function could exist in your own modules or in a binary library: the source of actual bytes for the function implementation are resolved by the linker. 因此extern C函数可以存在于您自己的模块或二进制库中:函数实现的实际字节源由链接器解析。 If the function signature is declared as a regular C++ function and not extern C, the compiler will mangle the symbolic name to encode type information from the function signature. 如果函数签名被声明为常规C ++函数而不是extern C,则编译器将破坏符号名称以编码函数签名中的类型信息。 This will make it incompatible with object code generated by other C++ compilers. 这将使其与其他C ++编译器生成的目标代码不兼容。 Therefore creating an extern C function allows you to share code between compilers in binary form. 因此,创建extern C函数允许您以二进制形式在编译器之间共享代码。 Note that you can't expose member functions this way, only old-style C functions. 请注意,您不能以这种方式公开成员函数,只能使用旧式C函数。

It doesn't have to be a function pointer. 它不必是函数指针。 You can specify the function declaration normally and prefix it with extern "C" , as shown in some Microsoft examples . 您可以正常指定函数声明,并以extern "C"作为前缀,如某些Microsoft示例所示。

If you use GetProcAddress() you are not allocating any memory. 如果使用GetProcAddress() ,则不会分配任何内存。 You simply get the memory address of the function inside the DLL that has already been loaded into memory (with LoadLibrary() , presumably). 您只需获取DLL中已加载到内存中的函数的内存地址LoadLibrary()可能是LoadLibrary() )。

Even when using function pointers (such as those returned by GetProcAddress) you don't have to use typedef , it's just that the code looks pretty ugly without it. 即使使用函数指针(如由GetProcAddress的返回),你不必使用typedef ,它只是代码看起来没有它很丑陋。 It's always hard to figure out what to write as well. 总是很难弄清楚要写什么。 I think it would be something like: 我想它会是这样的:

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

extern "C" {} is a C++ convention to declare that the enclosed functions are C functions -- not C++ functions. extern“C”{}是一个C ++约定,用于声明所包含的函数是C函数 - 而不是C ++函数。 C++ has a slightly different naming convention which conflicts with C. If you have a library written in C and want to use it in a C++ program, you have to use extern "C" {} to let the compiler know these are C functions. C ++的命名约定略有不同,与C冲突。如果你有一个用C语言编写的库并想在C ++程序中使用它,你必须使用extern“C”{}让编译器知道这些是C函数。 If the library was written in C++ I believe the extern "C" {} will cause an error. 如果库是用C ++编写的,我相信extern“C”{}会导致错误。

Note that extern has multiple meanings -- this specific case is a C++ convention and is unrelated to different uses of extern. 请注意,extern具有多种含义 - 这种特定情况是C ++约定,与extern的不同用法无关。 For example, 例如,

extern int count;

has a completely different meaning than extern "C" {}. 与extern“C”{}有完全不同的含义。

The typedef is separate from the extern "C" {} issue. typedef与extern“C”{}问题是分开的。 typedefs let you create aliases for common types that make more sense. typedefs允许您为更有意义的常见类型创建别名。 For example, declaring structs is often a verbose process. 例如,声明结构通常是一个冗长的过程。 I can use a typedef to shorten it: 我可以使用typedef来缩短它:

struct mystruct {int a; int b};
typedef struct mystruct returncode;
// I can now declare a variable as type 'returncode'
returncode a;

Thus, in your example the HRESULT is really an alias for (*CREATEDEVICE)() although I believe you have to put it before the function (and not after). 因此,在你的例子中,HRESULT实际上是(* CREATEDEVICE)()的别名,虽然我相信你必须把它放在函数之前(而不是之后)。

One important aspect of specifying extern "C" linkage is that the function names do not get mangled, which is the default for C++ names. 指定extern "C"链接的一个重要方面是函数名称不会被破坏,这是C ++名称的默认值。

In order for your library's functions to be able to be loaded using GetProcAddress , you need to either add the function to the .def file , use __declspec(dllexport) or use extern "C" . 为了能够使用GetProcAddress加载库的函数,您需要将函数添加到.def文件 ,使用__declspec(dllexport)或使用extern "C"

To answer, in order: 要按顺序回答:

  • extern "C" functions are used for interop with C from C++. extern“C”函数用于与C ++中的C互操作。 Using them has the consequence that C code can call the function. 使用它们的结果是C代码可以调用该函数。 As the windows API is a C API all functions are extern "C" to ensure that C and C++ code can make use of the API. 由于Windows API是一个C API,所有函数都是extern“C”,以确保C和C ++代码可以使用API​​。

  • In order for c++ programs to interoperate with other languages, including C, as a convention , functions are exported using extern "C". 为了使c ++程序与其他语言(包括C)互操作作为约定,使用extern“C”导出函数。 Which is why a lot of dll code does this. 这就是为什么很多DLL代码都会这样做的原因。 It is not a technical requirement however. 然而,这不是技术要求。

  • So no, it does NOT have to be a C function pointer. 所以不,它不一定是C函数指针。

  • You don't have to use typedef's either. 您也不必使用typedef。

The example code provided is from a header file that is publishing the exports of a DLL twice - Once as the set of extern "C" methods that are exported so that the dll can be statically linked. 提供的示例代码来自头文件,该头文件两次发布DLL的导出 - 一次作为导出的外部“C”方法的集合,以便dll可以静态链接。 the other as a set of function pointer types, so that the dll can be dynamically loaded, and the function pointer types used with GetProcAddress. 另一个作为一组函数指针类型,这样dll可以动态加载,而函数指针类型与GetProcAddress一起使用。

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

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