zoukankan      html  css  js  c++  java
  • extern "C"的作用

    一、概述

      在C语言的头文件中,经常可以看到如下的代码,那这个是什么作用呢?

    #ifdef __cplusplus
    extern "C" {
    #endif
     
    /*...*/
     
    #ifdef __cplusplus
    }
    #endif

      extern "C"起作用的时候是在:C++调用C中的函数。由于C++和C是两种不同的编译和连接方法,所以在交叉调用的时候,就需要增加一些机制起到让两者无缝兼容的目的。而extern "C"正是这一种机制,规定在编译C++源文件时,那些调用自C文件的部分(需要用extern "C"修饰其在头文件中的声明),按照与C文件编译兼容的方式进行。

      那么显然在不涉及C++调用C中函数的情况,extern "C"是不起作用的。在编译C文件的时候,编译器是不会自动添加“__cplusplus”的宏定义;而在编译C++文件的时候,编译器会自动的对“__cplusplus”进行宏定义。

    二、C++的编译

    1、测试源码

    • config.c
    void config(void)
    {
        return ;
    }
    • config.h
    #ifndef    __CONFIG_H
    #define    __CONFIG_H
    
    extern void config(void);
    
    #endif
    • main.cpp
    #include "config.h"
    int main(void)
    {
    ...
    config();
    ...
    }

    2、测试

      使用arm-none-eabi-gcc交叉编译链对以上源码进行编译,arm-none-eabi-gcc工具编译config.c,arm-none-eabi-g++编译main.cpp,结果如下:

      config.o.lst

      94                      .section    .text.config,"ax",%progbits
      95                      .align    2
      96                      .global    config
      97                      .thumb
      98                      .thumb_func
     100                  config:
     101                  .LFB30: 
     100                  config:
     101                  .LFB30:
      61:../User/config.c **** 
      62:../User/config.c **** void config(void)
      63:../User/config.c **** {
     102                      .loc 1 63 0
     103                      .cfi_startproc
     104                      @ args = 0, pretend = 0, frame = 0
     105                      @ frame_needed = 1, uses_anonymous_args = 0
     106                      @ link register save eliminated.
     107 0000 80B4             push    {r7}
     108                      .cfi_def_cfa_offset 4
     109                      .cfi_offset 7, -4
     110 0002 00AF             add    r7, sp, #0
     111                      .cfi_def_cfa_register 7
      64:../User/bsp_led.c ****     return ;
     112                      .loc 1 64 0
     113 0004 00BF             nop
      65:../User/bsp_led.c **** }
     114                      .loc 1 65 0
     115 0006 BD46             mov    sp, r7
     116                      @ sp needed
     117 0008 5DF8047B         ldr    r7, [sp], #4
     118 000c 7047             bx    lr

      main.o.lst

      35:../User/main.cpp ****     config();
      42                         .loc 1 35 0
      43 0008 FFF7FEFF         bl    _Z6configv

     在连接程序的最后阶段,出现错误提示:../User/main.cpp:35: undefined reference to `config()'

    原因分析:

      因为config.c程序在编译的时候被翻译成了.text.config代码段,而此段中存在一个函数标号config。也就是说config.c文件的config()函数在编译的时候,其对应的标号是config

      而main.cpp文件调用该函数的地方,编译后却使用了标号_Z6configv。那么显然在连接的时候,连接器无法将这两个标号连接到一起,而出现上述错误。

    3、使用extern “C”关键字

      修改config.h,内容为

    #ifndef    __CONFIG_H
    #define    __CONFIG_H
    
    extern "C" void config(void);
    
    #endif

      重新编译这些文件,结果main.cpp的编译结果出现了变化,而最终程序连接也通过了

      35:../User/main.cpp ****     config();
      42                      .loc 1 35 0
      43 0008 FFF7FEFF         bl    config

    原因分析:

      由于extern "C"修饰了void config(void),所以在main.cpp调用该函数的时候按照C文件的编译方式进行编译,所以其对应的标号为config。config函数所在的文件config.c文件编译出的标号与之一致,就能成功的连接。

    参考博客:C++项目中的extern "C" {}

  • 相关阅读:
    jQuery 语法
    jQuery 简介
    把数据存储到 XML 文件
    XML 注意事项
    XML DOM (Document Object Model) 定义了访问和操作 XML 文档的标准方法。
    通过 PHP 生成 XML
    XML 命名空间(XML Namespaces)
    XML to HTML
    XMLHttpRequest 对象
    使用 XSLT 显示 XML
  • 原文地址:https://www.cnblogs.com/amanlikethis/p/3831483.html
Copyright © 2011-2022 走看看