当前位置:   article > 正文

extern C的用法_"extern \"c\" {}的用法"

"extern \"c\" {}的用法"

       extern "C"的用法简单来说就是为了方便C与CPP的混合编译。为了支持函数的重载,C++对全局函数的处理方式与C有明显的不同。 extern “C”的主要作用就是为了能够正确实现C++代码调用其他C语言代码。加上extern “C”后,会指示编译器这部分代码按C语言的进行编译,而不是C++的。由于C++支持函数重载,因此编译器编译函数的过程中会将函数的参数类型也加到编译后的代码中,而不仅仅是函数名;而C语言并不支持函数重载,因此编译C语言代码的函数时不会带上函数的参数类型,一般之包括函数名。 

        那么 extern "C"如何使用呢? 假设在某一个头文件中定义了这样一个函数

int fun(int a, int b);  

而这个函数的实现位于一个.c文件中,同时,在.cpp文件中调用了这个函数。那么,当CPP编译器编译这个函数的时候,就有可能会把这个函数名改成_foo_int_int(也可能为其他),这里的ii表示函数的第一参数和第二参数都是整型。而C编译器却有可能将这个函数名编译成_foo。也就是说,在CPP编译器得到的目标文件中,foo()函数是由_foo_int_int符号来引用的,而在C编译器生成的目标文件中,foo()函数是由_foo指代的。但连接器工作的时候,它可不管上层采用的是什么语言,它只认目标文件中的符号。于是,连接器将会发现在.cpp中调用了foo()函数,但是在其它的目标文件中却找不到_foo_int_int这个符号,于是提示连接过程出错。extern “C” {}这种语法形式就是用来解决这个问题的。

  1. //test_extern_c.h
  2. #ifndef __TEST_EXTERN_C_H__
  3. #define __TEST_EXTERN_C_H__
  4. //#ifdef __cplusplus
  5. //extern "C" {
  6. //#endif
  7. extern int fun(int a, int b);
  8. //#ifdef __cplusplus
  9. //}
  10. //#endif /* end of __cplusplus */
  11. #endif
  1. //fun.c
  2. #include "test_extern_c.h"
  3. int fun(int a, int b)
  4. {
  5. return (a + b);
  6. }
  1. #include "test_extern_c.h"
  2. #include<iostream>
  3. using namespace std;
  4. int main()
  5. {
  6. int a, b;
  7. cin >> a >> b;
  8. cout << fun(a, b) << endl;;
  9. return(0);
  10. }

 

上面我们将extern “c”部分注释掉了,发现

 

错误 LNK2019 无法解析的外部符号 "int __cdecl fun(int,int)" (?fun@@YAHHH@Z),该符号在函数 "int __cdecl printadd(int,int)" (?printadd@@YAHHH@Z)

然后我们将extern “c”部分加上

  1. //test_extern_c.h
  2. #ifndef __TEST_EXTERN_C_H__
  3. #define __TEST_EXTERN_C_H__
  4. #ifdef __cplusplus
  5. extern "C" {
  6. #endif
  7. extern int fun(int a, int b);
  8. #ifdef __cplusplus
  9. }
  10. #endif /* end of __cplusplus */
  11. #endif

现在能够编译通过。

 

 

extern “C”的含义

 

  • 首先,被它修饰的目标是“extern”的,被extern “C”限定的函数或变量是extern类型的; 
  • 其次,被它修饰的目标是“C”的。 

extern是C/C++语言中表明函数和全局变量作用范围(可见性)的关键字,该关键字告诉编译器,其声明的函数和变量可以在本模块或其它模块中使用。 通常,在模块的头文件中对本模块提供给其它模块引用的函数和全局变量以关键字extern声明。例如,如果模块B欲引用该模块A中定义的全局变量和函数时只需包含模块A的头文件即可。这样,模块B中调用模块A中的函数时,在编译阶段,模块B虽然找不到该函数,但是并不会报错;它会在链接阶段中从模块A编译生成的目标代码中找到此函数。 与extern对应的关键字是static,被它修饰的全局变量和函数只能在本模块中使用。因此,一个函数或变量只可能被本模块使用时,其不可能被extern “C”修饰

总结:

1.如果C++调用一个C语言编写的.DLL时,当包括.DLL的头文件或声明接口函数时,应加extern “C”{}。

  1. /* c语言头文件:cExample.h */
  2. #ifndef C_EXAMPLE_H
  3. #define C_EXAMPLE_H
  4. extern int add(int x,int y); //注:写成extern "C" int add(int , int ); 也可以
  5. #endif
  6. /* c语言实现文件:cExample.c */
  7. #include "cExample.h"
  8. int add( int x, int y )
  9. {
  10.  return x + y;
  11. }
  12. // c++实现文件,调用add:cppFile.cpp
  13. extern "C"
  14. {
  15.  #include "cExample.h"
  16. }
  17. int main(int argc, char* argv[])
  18. {
  19.  add(2,3);
  20.  return 0;
  21. }

 

 

2.在C中引用C++语言中的函数和变量时,C++的头文件需添加extern “C”,但是在C语言中不能直接引用声明了extern “C”的该头文件,应该仅将C文件中将C++中定义的extern “C”函数声明为extern类型

 

 

  1. //C++头文件 cppExample.h
  2. #ifndef CPP_EXAMPLE_H
  3. #define CPP_EXAMPLE_H
  4. extern "C" int add( int x, int y );
  5. #endif
  6. //C++实现文件 cppExample.cpp
  7. #include "cppExample.h"
  8. int add( int x, int y )
  9. {
  10.  return x + y;
  11. }
  12. /* C实现文件 cFile.c
  13. extern int add( int x, int y );
  14. int main( int argc, char* argv[] )
  15. {
  16.  add( 2, 3 );
  17.  return 0;
  18. }

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/264335
推荐阅读
相关标签
  

闽ICP备14008679号