但是在C语言中不能直接引用声明了extern "C"的该头文件

时间:2021-10-19 04:15:02

修饰符用于声明在外部实现的要领。extern 修饰符的常见用法是在使用 Interop 处事调入非

托管代码时与 DllImport 属性一起使用;在这种情况下,该要领还必需声明为 static,如下面的示例所示:[DllImport("avifil32.dll")]
private static extern void AVIFileInit();

注意 
extern 关键字还可以界说外部措施集别号,使得可以从单个措施集中引用同一组件的差别版本。

将 abstract(C# 参考)和 extern 修饰符一起使用来改削同一成员是错误的。使用 extern 修饰符意味着要领在 C# 代码的外部实现,而使

用 abstract 修饰符意味着在类中未供给要领实现。注意 
extern 关键字在使用上比在 C++ 中有更多的限制。若要与 C++ 关键字进行对照,请参见 C++ Language Reference 中的 Using extern to

Specify Linkage。

在该示例中,措施接收来自用户的字符串并将该字符串显示在动静框中。措施使用从 User32.dll 库导入的 MessageBox 要领。

using System; using System.Runtime.InteropServices; class MainClass { [DllImport("User32.dll")] public static extern int MessageBox(int h, string m, string c, int type); //hovertree.com static int Main() { string myString; Console.Write("Enter your message: "); myString = Console.ReadLine(); return MessageBox(0, myString, "My Message Box", 0); } }

此示例使用 C 措施创建一个 DLL,不才一示例中将从 C# 措施挪用该 DLL。

[cpp] 

 

// cmdll.c 何问起 // compile with: /LD int __declspec(dllexport) SampleMethod(int i) { return i*10; }

该示例使用两个文件 CM.cs 和 Cmdll.c 来说明 extern。C 文件是示例 2 中创建的外部 DLL,它从 C# 措施内挪用。

[c-sharp]  

 

// cm.cs using System; using System.Runtime.InteropServices; public class MainClass { [DllImport("Cmdll.dll")] public static extern int SampleMethod(int x); //hovertree.com static void Main() { Console.WriteLine("SampleMethod() returns {0}.", SampleMethod(5)); } }

输出

SampleMethod() returns 50.
生成项目:
使用 Visual C++ 命令行将 Cmdll.c 编译为 DLL:cl /LD Cmdll.c使用命令行编译 CM.cs:csc CM.cs这将创建可执行文件 CM.exe。运行此程

序时,SampleMethod 将值 5 通报到 DLL 文件,该文件将此值乘以 10 返回extern "C"
  extern "C" 包罗双重含义,从字面上即可得到:首先,被它修饰的方针是“extern”的;其次,被它修饰的方针是“C”的。让我们来详细解读这两重含义。

  (1) 被extern "C"限定的函数或变量是extern类型的;

  extern是C/C++语言中表白函数和全局变量感化范畴(可见性)的关键字,该关键字报告编译器,其声明的函数和变量可以在本模块或其它模块中使用。记住,下列语句:

  extern int a;

  仅仅是一个变量的声明,其并不是在界说变量a,并未为a分配内存空间。变量a在所有模块中作为一种全局变量只能被界说一次,否则会呈现连接错误。

  凡是,在模块的头文件中对本模块供给给其它模块引用的函数和全局变量以关键字extern声明。例如,如果模块B欲引用该模块A中界说的全局变量和函数时只需包罗模块A的头文件即可。这样,模块B中挪用模块A中的函数时,在编译阶段,模块B虽然找不到该函数,但是并不会报错;它会在连接阶段中从模块A编译生成的方针代码中找到此函数。

实例:

[cpp]  

 

//cppExample.h #ifndef MODULE_A_H #define MODULE_A_H extern int foo( int x, int y );// 声明函数,其为extern类型 #endif ////////////////////////////////////////////////////////////////////////////////////////////// //hovertree.com ////////////////////////////////////////////////////////////////////////////////////////////// //cppExample.cpp #include <iostream> #include "cppExample.h" using namespace std; int foo( int x, int y )//界说extern类型的函数 { cout << x+y; return 0; } //////////////////////////////////////////////////////////////////////////////////////////////////// //main.cpp #include <iostream> #include"cppExample.h" using namespace std; void main() { foo(5,6);//函数挪用 } /////////////////////////////////////////////////////////////////////////////////////////////////////


这里呢,就有了个疑问:其实如果再cppExample.h中声明了一个全局函数int foo(Int x, int y),然后在main.cpp中挪用foo函数,其都是一样的,都可以告成编译,函数告成挪用,那这个extern到底有什么用呢,不是节外生枝么?(暂放,以后增补)

    与extern对应的关键字是static,被它修饰的全局变量和函数只能在本模块中使用。因此,一个函数或变量只可能被本模块使用时,其不成能被extern “C”修饰。


(2) 被extern "C"修饰的变量和函数是凭据C语言方法编译和连接的;
  未加extern “C”声明时的编译方法
  首先看看C++中对类似C的函数是怎样编译的。

  作为一种面向东西的语言,C++撑持函数重载,而过程式语言C则不撑持。函数被C++编译后在标记库中的名字与C语言的差别。例如,假设某个函数的原型为:


  void foo( int x, int y );

  该函数被C编译器编译后在标记库中的名字为_foo,而C++编译器则会孕育产生像_foo_int_int之类的名字(差此外编译器可能生成的名字差别,但是都给与了不异的机制,生成的新名字称为“mangledname”)。_foo_int_int这样的名字包罗了函数名、函数参数数量及类型信息,C++就是靠这种机制来实现函数重载的。例如,在C++中,函数void foo( int x, int y )与void foo( int x, float y)编译生成的标记是不不异的,后者为_foo_int_float。


  同样地,C++中的变量除撑持局部变量外,还撑持类成员变量和全局变量。用户所编写措施的类成员变量可能与全局变量同名,我们以"."来区分。而素质上,编译器在进行编译时,与函数的措置惩罚惩罚相似,也为类中的变量取了一个并世无双的名字,这个名字与用户措施中同名的全局变量名字差别。

  未加extern "C"声明时的连接方法
  假设在C++中,模块A的头文件如下:
     

[cpp]