extern "C" to resolve usage

extern "C" to resolve usage

1 Introduction
   C ++ to create the original intention of the language is "A of Better C" , but that does not mean C ++ similar to C compiler and connections with the language of global variables and functions used in C language identical. As a desire and C -compatible language,
C ++ retains some of the features of the process of language (the world known as " object does not completely face " ), so it can not belong to any class defined global variables and functions. However, C ++ , after all, is an object-oriented programming language
In order to support overloading of functions, C ++ 's handling of the global functions of C are quite different.
 
2. Speaking from the standard header files
  Some companies have given below a face questions:
  Interview questions
  Why is the standard header file has a structure similar to the following?
    #ifndef __INCvxWorksh
    #define __INCvxWorksh
    #ifdef __cplusplus
    extern "C" {
    #endif
    /*...*/
    #ifdef __cplusplus
    }
    #endif
    #endif /* __INCvxWorksh */
  analysis
  Clearly, the header file to compile macros "__INCvxWorksh #ifndef , #define __INCvxWorksh , #endif"  role is to prevent the header file from being referenced.
  Then
#ifdef __cplusplus
extern "C" {
  #endif
  #ifdef __cplusplus
}
#endif
  What role is it? We will be one by one below.
 
3. Deep Inside extern "C"
   extern "C"  contains a double meaning, you can get literally: First of all, it was modified goal is to "extern" ; second, it was modified goal is "C" of. Let's take a detailed interpretation of both heavy meaning.
  Is extern "C" function or variable is defined extern type;
   extern is C / C ++ language indicated scope functions and global variables (visibility) of the keyword, which tells the compiler function and variable declarations that may be used in the other module or modules. Remember, the following statements:
   extern int a;
  Just declare a variable, the variable is not defined in a , not as a allocate memory space. Variable a as a global variable in all modules can only be defined once, or the connection error.
  通常,在模块的头文件中对本模块提供给其它模块引用的函数和全局变量以关键字 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万+

Guess you like

Origin blog.csdn.net/huaweizte123/article/details/53707255