zoukankan      html  css  js  c++  java
  • extern的用法小结

    [extern 变量] [extern 函数]解析

    这种情况下的extern说明变量或者函数声明在其他的源文件里,而不用include头文件的方式来引用该函数,在链接时,链接器在各个模块中搜索这个变量或者函数来进行最终链接。

    [extern “C”] 解析

    使用这种extern的情况多发生在使用C++调用由C写成的函数库时,此时编译过程中常发生编译器找不到C函数的问题,从而导致链接失败。为了解决这种情况,才引用了extern “C”这种用法。

    那为什么又会出现这种链接失败的情况呢?简单来是由于g++和gcc生成函数名称方式的不同造成的。C++语言在编译的时候为了解决函数的多态问题,不会直接使用程序中书写的函数名称,而会使用一种特别的方法经过中间变换过程生成一个全局唯一函数名。C库函数是没有经过函数名称变换得来的,当C++使用经过变换的函数名称去调没有变换过的函数时,肯定会出现链接失败的情况。

    这种特殊的转换方法叫做“名称的特殊处理(Name Mangling)”,比如C++将函数名和参数联合起来生成一个中间的函数名称,而C语言则不会,因此会造成链接时找不到对应函数的情况,此时C函数就需要用extern “C”进行链接指定,这告诉编译器,这是一个用C写成的库文件,请用C的方式来链接它们。

    下面我们使用一个简单的例子来说明这个问题。我们分别编译如下两段基本相同的程序,重点留意下函数”int f(void)”,在两种书写方式下的汇编语言表示方法。将源代码分别保存后,使用g++ -S test1.cpp和g++ -S test2.cpp编译生成汇编代码,对比如下,红色部分标出左右两部分不同的部分。

    //保存该文件为:test1.cpp
    #include <stdio.h>
    extern "C"
    {
    int f(void)
    {
    return 1;
    }
    }
    10  int main()
    11  {
    12  f();
    13  return 0;
    14  }
    15   
    //保存该文件为:test2.cpp
    #include <stdio.h>
     
     
    int f(void)
    {
    return 1;
    }
     
    10  int main()
    11  {
    12      f();
    13      return 0;
    14  }
    15   
       .file   "test1.cpp"
            .text
            .align 2
    .globl f
            .type   f, @function
    f:
    .LFB3:
            pushl   %ebp
    .LCFI0:
    10          movl    %esp, %ebp
    11  .LCFI1:
    12          movl    $1, %eax
    13          popl    %ebp
    14          ret
    15  .LFE3:
    16          .size   f, .-f
    17          .align 2
    18  .globl main
    19          .type   main, @function
    20  main:
    21  .LFB5:
    22          pushl   %ebp
    23  .LCFI2:
    24          movl    %esp, %ebp
    25  .LCFI3:
    26          subl    $8, %esp
    27  .LCFI4:
    28          andl    $-16, %esp
    29          movl    $0, %eax
    30          subl    %eax, %esp
    31          call    f
    32          movl    $0, %eax
    33          leave
    34          ret
    35  .LFE5:
    36          .size   main, .-main
    37          .section        .note.GNU-stack,"",@progbits
    38          .ident  "GCC: (GNU) 3.3.4"
    39   
            .file   "test2.cpp"
            .text
            .align 2
    .globl _Z1fv
            .type   _Z1fv, @function
    _Z1fv:
    .LFB3:
            pushl   %ebp
    .LCFI0:
    10          movl    %esp, %ebp
    11  .LCFI1:
    12          movl    $1, %eax
    13          popl    %ebp
    14          ret
    15  .LFE3:
    16          .size   _Z1fv, .-_Z1fv
    17          .align 2
    18  .globl main
    19          .type   main, @function
    20  main:
    21  .LFB5:
    22          pushl   %ebp
    23  .LCFI2:
    24          movl    %esp, %ebp
    25  .LCFI3:
    26          subl    $8, %esp
    27  .LCFI4:
    28          andl    $-16, %esp
    29          movl    $0, %eax
    30          subl    %eax, %esp
    31          call    _Z1fv
    32          movl    $0, %eax
    33          leave
    34          ret
    35  .LFE5:
    36          .size   main, .-main
    37          .section        .note.GNU-stack,"",@progbits
    38          .ident  "GCC: (GNU) 3.3.4"
    39   
  • 相关阅读:
    第二周c语言PTA作业留
    2018第零次作业
    总结报告
    第14/15周作业
    第七周作业
    第六周作业
    第四次作业
    第三次作业
    大学第二次作业
    大学的第一次作业
  • 原文地址:https://www.cnblogs.com/motadou/p/1562748.html
Copyright © 2011-2022 走看看