解決の使用にはextern「C」

解決の使用にはextern「C」

1.はじめに
   C ++ 言語の本来の意図を作成するためには、 「より良いCのA」 、それは意味しない C ++ に類似 のC コンパイラとで使用されるグローバル変数や関数の言語との接続 Cの 同じ言語を。欲望と同様に C 互換言語、
C ++は、 言語(として知られている世界のプロセスのいくつかの機能を保持 のオブジェクトが完全に面していないが 、)任意のクラスは、グローバル変数と関数を定義していない所属することができるようにします。しかし、 C ++は 、すべての後に、オブジェクト指向プログラミング言語であります
関数のオーバーロードをサポートするためには、 C ++ のグローバル関数のの取扱い Cは かなり異なっています。
 
2.標準ヘッダファイルから言えば
  一部の企業は、顔の質問の下に与えています:
  インタビューの質問
  なぜ標準ヘッダファイルには、次のような構造を持っていますか?
    #ifndefの__INCvxWorksh
    #define __INCvxWorksh
    #ifdefの__cplusplus
    extern "C" {
    #endifの
    /*...*/
    #ifdefの__cplusplus
    }
    #endifの
    #endifの/ * __INCvxWorksh * /
  分析
  明らかに、コンパイルマクロのヘッダファイル 「__INCvxWorksh #ifndefの の#define __INCvxWorksh #endifの」  役割が参照されてからヘッダファイルを防ぐためです。
  それから
#ifdefの__cplusplus
extern "C" {
  #endifの
  #ifdefの__cplusplus
}
#endifの
  それはどのような役割ですか?私たちは、以下の一つ一つになります。
 
3.ディープインサイドにextern "C"
   extern「C」は  二重の意味が含まれている、あなたは文字通り得ることができます:まず、それが変更された目標は、にある 「はextern」 ;第二、それが変更された目標は 「C」 の。両方の重い意味の詳細な解釈を見てみましょう。
  され にextern「C」 関数や変数が定義されている のextern タイプ。
   EXTERNで ある C / C ++ 言語は、他のモジュールまたはモジュールで使用することができるコンパイラ関数と変数の宣言を伝えるキーワードのスコープ関数およびグローバル変数(視認性)を示しました。、次の文を覚えておいてください:
   extern int型のA;
  ただ、変数が定義されていない、変数を宣言し ないように、メモリ空間を割り当てます。変数Aのすべてのモジュール内のグローバル変数は一度だけ定義することができるように、または接続エラー。
  通常,在模块的头文件中对本模块提供给其它模块引用的函数和全局变量以关键字 extern 声明 。例如,如果模块 B 欲引用该模块 A 中定义的全局变量和函数时只需包含模块 A 的头文件即可。这样,模块 B 中调用模块 A 中的函数时,在编译阶段,模块 B 虽然找不到该函数,但是并不会报错;它会在连接阶段中从模块 A 编译生成的目标代码中找到此函数。
   extern 对应的关键字是 static ,被它修饰的全局变量和函数只能在本模块中使用。因此,一个函数或变量只可能被本模块使用时,其不可能被 extern “C” 修饰。
  被 extern "C" 修饰的变量和函数是按照 C 语言方式编译和连接的;
  未加 extern “C” 声明时的编译方式
  首先看看 C++ 中对类似 C 的函数是怎样编译的。
  作为一种面向对象的语言, C++ 支持函数重载,而过程式语言 C 则不支持。函数被 C++ 编译后在符号库中的名字与 C 语言的不同。例如,假设某个函数的原型为:
void foo( int x, int y );
  该函数被 C 编译器编译后在符号库中的名字为 _foo ,而 C++ 编译器则会产生像 _foo_int_int 之类的名字(不同的编译器可能生成的名字不同,但是都采用了相同的机制,生成的新名字称为 “mangled name” )。
   _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 的头文件如下:
//  模块 A 头文件  moduleA.h
#ifndef MODULE_A_H
#define MODULE_A_H
int foo( int x, int y );
#endif
  在模块 B 中引用该函数:
//  模块 B 实现文件  moduleB.cpp
#include "moduleA.h"
foo(2,3);
  实际上,在连接阶段,连接器会从模块 A 生成的目标文件 moduleA.obj 中寻找 _foo_int_int 这样的符号!
  加 extern "C" 声明后的编译和连接方式
  加 extern "C" 声明后,模块 A 的头文件变为:
//  模块 A 头文件  moduleA.h
#ifndef MODULE_A_H
#define MODULE_A_H
extern "C" int foo( int x, int y );
#endif
  在模块 B 的实现文件中仍然调用 foo( 2,3 ) ,其结果是:
  ( 1 模块 A 编译生成 foo 的目标代码时,没有对其名字进行特殊处理,采用了 C 语言的方式;
  ( 2 连接器在为模块 B 的目标代码寻找 foo(2,3) 调用时,寻找的是未经修改的符号名 _foo
  如果在模块 A 中函数声明了 foo extern "C" 类型,而模块 B 中包含的是 extern int foo( int x, int y )  ,则模块 B 找不到模块 A 中的函数;反之亦然。
  所以,可以用一句话概括 extern “C” 这个声明的真实目的(任何语言中的任何语法特性的诞生都不是随意而为的,来源于真实世界的需求驱动。我们在思考问题时,不能只停留在这个语言是怎么做的,还要问一问它为什么要这么做,动机是什么,这样我们可以更深入地理解许多问题):
  实现 C++ C 及其它语言的混合编程。
明白了 C++ extern "C" 的设立动机,我们下面来具体分析 extern "C" 通常的使用技巧。
 
   4.extern "C"的惯用法
  ( 1 )在 C++ 中引用 C 语言中的函数和变量,在包含 C 语言头文件(假设为 cExample.h )时,需进行下列处理:
extern "C"
{
#include "cExample.h"
}
  而在 C 语言的头文件中,对其外部函数只能指定为 extern 类型, C 语言中不支持 extern "C" 声明,在 .c 文件中包含了 extern "C" 时会出现编译语法错误
  笔者编写的 C++ 引用 C 函数例子工程中包含的三个文件的源代码如下:
/* c 语言头文件: cExample.h */
#ifndef C_EXAMPLE_H
#define C_EXAMPLE_H
extern int add(int x,int y);     //注:写成extern "C" int add(int , int ); 也可以
#endif
/* c 语言实现文件: cExample.c */
#include "cExample.h"
int add( int x, int y )
{
  return x + y;
}
// c++ 实现文件,调用 add cppFile.cpp
extern "C"
{
  #include "cExample.h"        //注:此处不妥,如果这样编译通不过,换成 extern "C" int add(int , int ); 可以通过
}
int main(int argc, char* argv[])
{
  add(2,3);
  return 0;
}
  如果 C++ 调用一个 C 语言编写的 .DLL 时,当包括 .DLL 的头文件或声明接口函数时,应加 extern "C" {   }
   2 )在 C 中引用 C++ 语言中的函数和变量时, C++ 的头文件需添加 extern "C" ,但是在 C 语言中不能直接引用声明了 extern "C" 的该头文件,应该仅将 C 文件中将 C++ 中定义的 extern "C" 函数声明为 extern 类型。
  笔者编写的 C 引用 C++ 函数例子工程中包含的三个文件的源代码如下:
//C++ 头文件  cppExample.h
#ifndef CPP_EXAMPLE_H
#define CPP_EXAMPLE_H
extern "C" int add( int x, int y );
#endif
//C++ 实现文件  cppExample.cpp
#include "cppExample.h"
int add( int x, int y )
{
  return x + y;
}
/* C 实现文件  cFile.c
/*  这样会编译出错: #include "cExample.h" */
extern int add( int x, int y );
int main( int argc, char* argv[] )
{
  add( 2, 3 );
  return 0;
}
  如果深入理解了第 3 节中所阐述的 extern "C" 在编译和连接阶段发挥的作用,就能真正理解本节所阐述的从 C++ 引用 C 函数和 C 引用 C++ 函数的惯用法。对第 4 节给出的示例代码,需要特别留意各个细节。
发布了12 篇原创文章 · 获赞 6 · 访问量 2万+

おすすめ

転載: blog.csdn.net/huaweizte123/article/details/53707255