一、概述

  在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" {}

posted on 2014-07-08 14:44  amanlikethis  阅读(726)  评论(0编辑  收藏  举报