zoukankan      html  css  js  c++  java
  • #ifdef __cplusplus extern "C" { #endif的作用

    经常可以在C的头文件中看到如下代码:

    1 #ifdef __cplusplus 
    2     extern "C" { 
    3 #endif
    4 /* head file contents */
    5 #ifdef __cplusplus 
    6     }
    7 #endif

    那么这一段代码的作用又是什么呢?

    查询的时候发现一个非常好用的FAQ网站,原文链接如下: https://isocpp.org/wiki/faq/mixing-c-and-cpp#include-c-hdrs-nonsystem    

    FAQ:如何在C++代码中调用C函数?

    只需要使用extern "C"声明C函数(在你的C++代码中),然后调用它(在你的C或C++代码中)。举个例子:

     1     // C++ code
     2     extern "C" void f(int); // one way
     3     extern "C" {    // another way
     4         int g(double);
     5         double h();
     6     };
     7     void code(int i, double d)
     8     {
     9         f(i);
    10         int ii = g(d);
    11         double dd = h();
    12         // ...
    13     }

    函数的定义可能是下面这样:

     1     /* C code: */
     2     void f(int i)
     3     {
     4         /* ... */
     5     }
     6     int g(double d)
     7     {
     8         /* ... */
     9     }
    10     double h()
    11     {
    12         /* ... */
    13     }

    注意使用的是C++类型规则,而不是C的。所以你不能通过错误数量的参数,调用使用extern "C"声明的函数。举个例子:

    1     // C++ code
    2     void more_code(int i, double d)
    3     {
    4         double dd = h(i,d); // error: unexpected arguments
    5         // ...
    6     }

    FAQ:如何在C代码中调用C++函数?

    只需要使用extern "C"声明C++函数(在你的C++代码中),然后调用它(在你的C或C++代码中)。举个例子:

    1     // C++ code:
    2     extern "C" void f(int);
    3     void f(int i)
    4     {
    5         // ...
    6     }

    接下来f()函数可以被这样调用:

    1     /* C code: */
    2     void f(int);
    3     void cc(int i)
    4     {
    5         f(i);
    6         /* ... */
    7     }

    当然,这只适用于非成员函数。如果要在C调用成员函数(包括虚拟函数),则需要提供一个简单的包装器。例如:

    1     // C++ code:
    2     class C {
    3         // ...
    4         virtual double f(int);
    5     };
    6     extern "C" double call_C_f(C* p, int i) // wrapper function
    7     {
    8         return p->f(i);
    9     }

    现在C::f()可以被这样调用:

    1     /* C code: */
    2     double call_C_f(struct C* p, int i);
    3     void ccc(struct C* p, int i)
    4     {
    5         double d = call_C_f(p,i);
    6         /* ... */
    7     }

    如果你想要在C代码中调用重载函数,你必须具有不同名称的包装器供C代码调用。举个例子:

    1     // C++ code:
    2     void f(int);
    3     void f(double);
    4     extern "C" void f_i(int i) { f(i); }
    5     extern "C" void f_d(double d) { f(d); }

    现在f()函数可以被这样调用:

    1     /* C code: */
    2     void f_i(int);
    3     void f_d(double);
    4     void cccc(int i,double d)
    5     {
    6         f_i(i);
    7         f_d(d);
    8         /* ... */
    9     }

    注意,即使你不能(或不想)修改C++头,这些技术也可以用来从C代码中调用C++库。

    FAQ:怎么在C++代码中包含C标准头文件?

    要使用#include包含标准头文件(如<cstdio>),您不必做任何不寻常的事情。比如:

    1 // This is C++ code
    2 #include <cstdio>                // Nothing unusual in #include line
    3 int main()
    4 {
    5   std::printf("Hello world
    ");  // Nothing unusual in the call either
    6   // ...
    7 }

    如果你认为std::printf()调用的std::很不习惯,最好的办法就是克服它。换句话说,这是在标准库中使用名称的标准方法,所以您现在不妨开始习惯它。

    然而如果你正在使用C++编译器编译C代码,并且你不想把所有的printf()转换成std::printf()。幸运的是,在这种情况下,C代码会使用旧样式的头文件<stdio.h>而不是新样式的<cstdio.h>,并且命名空间的神奇之处将解决其他问题。

    1 /* This is C code that I'm compiling using a C++ compiler */
    2 #include <stdio.h>          /* Nothing unusual in #include line */
    3 int main()
    4 {
    5   printf("Hello world
    ");  /* Nothing unusual in the call either */
    6   // ...
    7 }

    最后一点建议:如果你的C头文件不是C标准库的一部分,我们有两种不同的指导建议。分别是你 can’t change the header,或你can change the header

    FAQ:如何在C++代码中引用非系统C头文件?

    如果你要引用非系统提供的C头文件,你需要把#include包装在extern "C" { /*...*/ }代码块中。这将会告诉C++编译器,声明在这个头文件中的函数是C函数。

     1 // This is C++ code
     2 extern "C" {
     3   // Get declaration for f(int i, char c, float x)
     4   #include "my-C-code.h"
     5 }
     6 int main()
     7 {
     8   f(7, 'x', 3.14);   // Note: nothing unusual in the call
     9   // ...
    10 }

    FAQ:怎么修改C头文件,让C++代码更容易通过#include引用?

    如果你包含了系统中没有提供的C头文件,如果你能改变C头文件,你应该强烈考虑在头中添加外部extern "C" {...}逻辑,以便C++用户更容易将其包含到C++代码中。由于C编译器不理解extern“C”,因此必须将extern“C”{}包装在一个#ifdef中,这样普通的C编译器就看不到它们。

    Step #1:在C头文件的最顶部放置下面几行(注:符号__cplusplus当且仅当编译器是C++编译器时才会被定义):

    1 #ifdef __cplusplus
    2 extern "C" {
    3 #endif

    Step #2:在C头文件的最底部放置下面几行

    1 #ifdef __cplusplus
    2 }
    3 #endif

    现在你可以在C++代码中#include你的C头文件,而不需要extern "C"

    1 // This is C++ code
    2 // Get declaration for f(int i, char c, float x)
    3 #include "my-C-code.h"   // Note: nothing unusual in #include line
    4 int main()
    5 {
    6   f(7, 'x', 3.14);       // Note: nothing unusual in the call
    7   // ...
    8 }

    Note: #define macros are evil in 4 different ways: evil#1evil#2evil#3, and evil#4. But they’re still useful sometimes. Just wash your hands after using them.(关于这一点,暂无研究,读者感兴趣可自行查看)

    FAQ:怎么在C++代码中调用非系统C函数f(int,char,float)?

    如果你有一个你想调用的C函数,并且由于某种原因,你不希望或者不想#include一个声明了该函数的C头文件,你可以使用extern "C"语法在C++代码中声明单个C函数。

    当然,您需要使用完整函数原型:

    1 extern "C" void f(int i, char c, float x);

    几个C函数块可以通过大括号组合:

    1 extern "C" {
    2   void   f(int i, char c, float x);
    3   int    g(char* s, const char* s2);
    4   double sqrtOfSumOfSquares(double a, double b);
    5 }

    然后你可以向调用C++函数一样调用这个函数:

    1 int main()
    2 {
    3   f(7, 'x', 3.14);   // Note: nothing unusual in the call
    4   // ...
    5 }

    FAQ:如何构造一个能被C代码调用的C++函数f(int,char,float)

    C++编译器必须知道f(int,char,float)能够通过extern "C"被C编译器调用。

    1 // This is C++ code
    2 // Declare f(int,char,float) using extern "C":
    3 extern "C" void f(int i, char c, float x);
    4 // ...
    5 // Define f(int,char,float) in some C++ module:
    6 void f(int i, char c, float x)
    7 {
    8   // ...
    9 }

    extern“C”告诉编译器,发送到链接器的外部信息应该使用C调用约定和名称改写(例如,前面有一个下划线)。由于C不支持名称重载,因此不能使多个重载函数同时可由C程序调用。

    另外附上另外一篇文件,从原理上较为清楚的说明了extern C的作用及原因:https://www.geeksforgeeks.org/extern-c-in-c/ 

  • 相关阅读:
    计算一个整数的二进制中1的个数
    Java 操作 EXCEL
    WIN7 64位配置Oracle SQL Developer工具
    phpstrom+xdebug调试PHP代码
    Zend Server安装后首次运行就出现Internal Server Error的解决
    在C语言中使用scanf语句时遇到的问题总结
    ElementUI中scrollbar的使用解析
    前端模拟手机屏幕图片渐隐渐现效果实现
    谈谈怎么学习编程?
    underScore学习1:匿名函数中call(this)的作用
  • 原文地址:https://www.cnblogs.com/taouu/p/14672695.html
Copyright © 2011-2022 走看看