• C++中extern "C"的用法


      extern关键字可以置于变量或者函数前,以标示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义。这里起到的是声明作用范围的用处。另外,extern还可以与”C”连用,作为链接指示。本文就此进行实例说明如下:

    一、C++名字修饰(Name Mangling)

    首先需要从C++的重载说起,在C++中函数重载指的是几个函数的函数名相同,参数列表不同。那么当生成obj中间文件/目标文件的时候,C++编译器如何区分这几个重载函数呢?可以通过把原函数名与参数信息结合,产生一个独特的内部名字,这种技术叫做名字修饰(Name Mangling)。名字修饰规则没有一个标准,所以不同的编译器的名字修饰规则也不一样。

    下面是一组函数,其中f()函数重载了:

    1
    2
    3
    int f (void) { return 1; }
    int f (int) { return 0; }
    void g (void) { int i = f(), j = f(0); }

    f(void)和f(int)是不同的函数,除了函数名相同以外没有任何关系。当生成obj目标文件时,为了区分它们,C++编译器根据参数信息进行了名字修饰:

    1
    2
    3
    int __f_v (void) { return 1; }
    int __f_i (int) { return 0; }
    void __g_v (void) { int i = __f_v(), j = __f_i(0); }

    注意g()也被名字修饰了,虽然没有任何名字冲突。名字修饰应用于C++的任何符号。

    二、为什么要使用extern “C”?

    C语言中没有名字修饰(Name Mangling),因为C语言不支持函数重载。但是如果C++中含有C代码,在编译时C++编译器对C代码的函数也会进行名字修饰,函数名变了以后,将导致在C运行库中找不到对应函数,发生链接错误。

    1
    2
    3
    4
    5
    6
    7
    8
    // 将下面的代码保存为.cpp文件,并用C++编译器编译
    int printf(const char *format,...);
       
    int main()
    {
      printf("GeeksforGeeks");
      return 0;
    }

    输出:

    1
    2
    3
    /tmp/ccQBO9Im.o:在函数‘main'中:
    test.cpp:(.text+0xf):对‘printf(char const*, ...)'未定义的引用
    collect2: 错误:ld 返回 1

    为了防止C++编译器对C代码进行名字修饰,我们将C代码用extern “C”进行链接指定,告诉编译器,在生成中间文件时,不要对这部分代码进行名字修饰,而是生成符合C规则的中间符号名。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    extern "C"
    {
      int printf(const char *format,...);
    }
      
    int main()
    {
      printf("Hello!");
      return 0;
    }

    添加了extern “C”链接指示后,上面的代码就能够正常运行了。

    附:所有的C风格的头文件(stdio.h, string.h, … 等等)都有在extern “C”下声明,形式如下:

    1
    2
    3
    4
    5
    6
    7
    #ifdef __cplusplus 
    extern "C" {
    #endif
      /* Declarations of this file */
    #ifdef __cplusplus
    }
    #endif
  • 相关阅读:
    cocos2d中sprite动画接口及动画实现思路总结
    iOS开发:小技巧积累
    cocos2d使用定时器
    Eclipse报错:cannot connect to VM
    Myeclipse console 端没有 tomcat 启动的log信息
    MyEclipse Web项目不能自动编译
    在MyEclipse中如何查看Spring/Hibernate/Struts/JDK等源码的方法
    【KMS】查看Windows的环境变量
    【KMS】如何预防用户多次点击提交按钮
    MyEclipse中选择一行的快捷键
  • 原文地址:https://www.cnblogs.com/new-comer/p/5162396.html
Copyright © 2020-2023  润新知