• extern "C"详解


    extern 关键字:

      首先还是先看一下 extern 关键字的作用:extern关键字可以用于声明变量或函数,以标示变量或函数的定义在别的文件中,提示编译器遇到此变量或函数时在其他模块中寻找其定义。

      通常情况下,比如我们在头文件  "b.h"  中声明了一个函数,然后在 "b.cpp" 中实现了该函数,当在 "main.cpp" 中调用 "b.h" 中声明的函数时,只需在 ""main.cpp" 中 #include "b.h" 就可以了。例子如下:

    //b.h
    
    #pragma once
    #include <iostream>
    
    using namespace std;
    
    void test();
    //b.cpp
    
    #include "b.h"
    
    void test()
    {
        cout << "hello world" << endl;
    }
    //main.cpp
    #include "b.h"
    
    int main()
    {
        test();
        system("pause");
        return 0;
    }

      除了通过 #include "b.h" 这样的方式能调用到 "b.h" 中的函数外,还有下面这种方式也能调用到"b.h" 的函数。

    //main.cpp

    //#include "b.h" //在这里,不注释掉也是可以得,但是在对于 变量 来说时就必须注释掉了 #include <iostream> using namespace std; extern void test();//告诉编译器test()函数声明在其他文件中 int main() { test(); system("pause"); return 0; }

      上面是对于函数而言,那么要是在 "b.h" 中定义了一个全局变量 int x,(记住是全局变量哦!)现在我们想在 "main.cpp" 中访问变量 x, 那该怎么办呢? 会不会 #include "b.h" 后就可以直接访问了呢?我们先试一下:

    //b.h
    
    #pragma once
    #include <iostream>
    
    using namespace std;
    
    int x = 10;
    
    void test();
    //main.cpp
    #include "b.h"
    
    int main()
    {
        cout << "x=" << x << endl;
        system("pause");
        return 0;
    }

      我们在 "main.cpp" 中输出变量 x, 此时编译时没有问题的,但是当运行时,它就会报错:fatal error LNK1169: 找到一个或多个多重定义的符号。  因为在main.cpp中包含b.h头文件后,在预处理阶段头文件展开,于是相当于在main.cpp中和b.h中都定义了全局变量,两个地方定义就冲突了。 那么现在我们有没有其他方式能在 "main.cpp" 中访问到变量 x 呢?当然有,通过 "extern" 关键字能达到目的。用法如下:

    //main.cpp
    //#include "b.h" //一定要注释掉
    #include <iostream>
    
    using namespace std;
    
    extern int x;
    
    int main()
    {
        cout << "x=" << x << endl;
        system("pause");
        return 0;
    }

      说了那么多废话,终于把 extern 关键字说清楚了。(我想我是说清楚了,嘿嘿嘿), 接下来这个才是今天的狠角色。

    extern "C" 

      要说清楚 extern "C" 是怎么一回事,还得先说说C++函数重载的那些事。C++有函数重载,而C语言是没有函数重载的。函数重载是指两个或多个函数之间函数名相同,参数列表不同,参数列表不同可以是参数的个数不同,或者是参数的个数相同但参数类型不同,需要注意的是如果函数名相同,参数列表完全相同但返回值类型不同是不能构成函数重载的。C++有函数重载是因为当生成obj中间文件/目标文件的时候,C++编译器把原函数名与参数信息结合,产生了一个独特的内部名字,比如有两个函数 void foo(int x) 和 void foo(void) ,最终产生的内部名字就是 _foo_int 和 _foo_void (实际产生的内部名字的命名规则应该不是这样的,这里我们并不关心它的命名规则是怎样的,只需要体会这个意思就可以了),通过这样编译器就能区分 void foo(int x) 和 void foo(void)这两个函数了。但是在C语言里面,并不会产生这样的内部名字,如果C语言里面有两个函数 void foo(int x) 和void foo(void),那么当生成obj中间文件/目标文件的时候,产生的名字就是 _foo 和 _foo 这样两个名字相同,C编译器就不能将两个函数区分开了,所以C语言里面也就没了函数重载。

      正是由于C++编译器 和 C编译器对函数名处理方式的不同,当我们的 C++ 程序调用 C 程序或者 C 程序调用 C++程序时就会存在问题。 有了问题那当然就得解决,于是就有了 extern "C" 的出现。

      所以说到底 extern "C" 的作用是用来解决名字匹配问题,实现 C 与 C++ 的混合编程。摆这么一句话在这里显得很苍白无力,还是举例说明一下。

    C++ 调用 C 语言函数:

    //a.h
    #include <stdio.h>
    
    void test(int x, double y);
    //a.c
    #include "a.h"
    
    void test(int x, double y)
    {
        printf("hello world
    ");
    }

      上面的test函数是 C 语言实现的,我们在 "main.cpp" 进行调用,首先通过如下方式进行调用:

    //main.cpp
    
    #include "a.h"
    
    int main()
    {
        test(1,1.2);
        getchar();
        return 0;
    }

      通过上面这种方式调用,编译能通过,但是运行时就报错了:fatal error LNK1120: 1 个无法解析的外部命令说明在 main.cpp 里面的 test 并没有被找到。解决这个问题就需要 extern "C" 出场了,如下所示:

    //main.cpp
    extern "C"{
    #include "a.h"
    }
    
    
    int main()
    {
        test(1,1.2);
        getchar();
        return 0;
    }

      通过以上这种方式当然就能成功运行了,extern "C" 的作用就是告诉 C++ 编译器你不要把我的 "a.h" 里的内容当C++语法来编译,给我原封不动的当 C 语言的语法来编译。当然也可以换用下面的这种写法: 

    //main.cpp
    #include <iostream>
    using namespace std;
    
    extern "C" void test(int x, double y);
    int main()
    {
        test(1,1.2);
        getchar();
        return 0;
    }

    C 调用 C++函数:

      上面给大家展示了C++语言如何调用C函数,那么C语言又如何调用C++函数呢?

     

    //b.h
    #pragma noce
    #include <iostream>
    using namespace std;
    
    #ifdef __cplusplus  
    extern "C" {
    #endif 
    
        void test();
    
    #ifdef __cplusplus  
    }
    #endif  
    //b.cpp
    
    #include "b.h"
    
    void test()
    {
        cout << "hello world" << endl;
    }
    //main.c
    #include <stdio.h>
    
    extern void test();
    int main()
    {
        test();
        getchar();
        return 0;
    }
    https://i.cnblogs.com/posts?categoryid=0
  • 相关阅读:
    Java Concurrency
    Java Annotation,Java注解
    Think in java, notes
    嵌套事务
    java dynamic proxy,动态代理
    埃里克·雷蒙德
    HDU1222 Wolf and Rabbit
    HUT1098 素MM
    HDU1568 Fibonacci
    HDU1501 Zipper DFS+记忆化搜索
  • 原文地址:https://www.cnblogs.com/418ks/p/6837669.html
Copyright © 2020-2023  润新知