一、概述

  在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

                        .section    .text.config,"ax",%progbits
.align
.global config
.thumb
.thumb_func
config:
.LFB30:
config:
.LFB30:
:../User/config.c ****
:../User/config.c **** void config(void)
:../User/config.c **** {
.loc
.cfi_startproc
@ args = , pretend = , frame =
@ frame_needed = , uses_anonymous_args =
@ link register save eliminated.
80B4 push {r7}
.cfi_def_cfa_offset
.cfi_offset , -
00AF add r7, sp, #
.cfi_def_cfa_register
:../User/bsp_led.c **** return ;
.loc
00BF nop
:../User/bsp_led.c **** }
.loc
BD46 mov sp, r7
@ sp needed
5DF8047B ldr r7, [sp], #
000c bx lr

  main.o.lst

  :../User/main.cpp ****     config();
.loc
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的编译结果出现了变化,而最终程序连接也通过了

  :../User/main.cpp ****     config();
.loc
FFF7FEFF bl config

原因分析:

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

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

extern "C"的作用的更多相关文章

  1. extern C的作用详解

    extern "C"的主要作用就是为了能够正确实现C++代码调用其他C语言代码.加上extern "C"后,会指示编译器这部分代码按C语言的进行编译,而不是C+ ...

  2. C++编译时函数名修饰约定规则(很具体),MFC提供的宏,extern "C"的作用

    调用约定: __cdecl __fastcall与 __stdcall,三者都是调用约定(Calling convention),它决定以下内容:1)函数参数的压栈顺序,2)由调用者还是被调用者把参数 ...

  3. extern “C”的作用详解

    extern "C"的主要作用就是为了能够正确实现C++代码调用其他C语言代码.加上extern "C"后,会指示编译器这部分代码按C语言的进行编译,而不是C+ ...

  4. C++之 extern C的作用详解

    extern "C"的主要作用就是为了能够正确实现C++代码调用其他C语言代码.加上extern "C"后,会指示编译器这部分代码按C语言的进行编译,而不是C+ ...

  5. extern "c" 的作用

    作用:实现C和C++混合编程. 原理:C和C++编译器编译之后,函数名会编译成不同的名字,链接阶段名字查找会找不到目标,后面实例中会详解. 用法:①.c文件中定义的函数,.cpp文件要调用时,该.cp ...

  6. extern “C”的作用

    1.引言 C++语言的创建初衷是“a better C”,但是这并不意味着C++中类似C语言的全局变量和函数所采用的编译和连接方式与C语言完全相同.作为一种欲与C兼容的语言,C++保留了一部分过程 式 ...

  7. [转]extern "C"的作用

    extern "C"的主要作用就是为了能够正确实现C++代码调用其它C语言代码. 加上extern “C”后,会指示编译器将这部分代码按C语言进行编译,而不是C++的.这是因为C+ ...

  8. extern C的作用具体解释

    转载于:http://www.cnblogs.com/rollenholt/archive/2012/03/20/2409046.html 1.引言 C++语言的创建初衷是"a better ...

  9. 你真的知道C语言里extern "C" 的作用吗?

    经常在C语言的头文件中看到下面的代码: #ifdef __cplusplus extern "C" { #endif // all of your legacy C code he ...

随机推荐

  1. 探索高效jQuery的奥秘

    讨论jQuery和javascript性能的文章并不罕见.然而,本文我计划总结一些速度方面的技巧和我本人的一些建议,来提升你的jQuery和javascript代码.好的代码会带来速度的提升.快速渲染 ...

  2. PHP读书笔记(2)-变量与数据结构

    php中的数据类型: 一.8种主要数据类型 标量类型 1.整型(int|integer):八进制.十进制.十六进制.超过整型存储范围,会产生溢出. 整型数的字长和平台有关,尽管通常最大值是大约二十亿( ...

  3. Spring 4.2 annotation event Publisher/Listener

    http://spring.io/blog/2015/02/11/better-application-events-in-spring-framework-4-2 Better applicatio ...

  4. 【转载】Hadoop和大数据:60款顶级大数据开源工具

    一.Hadoop相关工具 1. Hadoop Apache的Hadoop项目已几乎与大数据划上了等号.它不断壮大起来,已成为一个完整的生态系统,众多开源工具面向高度扩展的分布式计算. 支持的操作系统: ...

  5. Python 基础【第十篇】内置类型

    一.integral 类型 Python提供了两种integral类型,即int(整数)与bool(布尔值). 1.1.整数 整数的相关运算符.函数.数据类型转换 1.1.1.整数的运算符 前面已经讲 ...

  6. Greedy

    在现实世界中,有这样一类问题:它有n个输入,而它的解就由这n个输入的某个子集组成,不过这个子集必须满足某些事先给定的条件.把那些必须满足的条件称为约束条件:而把满足约束条件的子集称为该问题的可行解.问 ...

  7. 你了解C语言中的关键字volatile吗?

    我们在学习C语言的32个关键字时,大家都不太注意volatile这个关键字,volatile是一个类型修饰符.volatile的中文意思是“易变的”.那么在程序中我们在什么情况下才使用他呢?我们在分析 ...

  8. uiatuomator命令启动apk,与查找多个相同控件

    背景:在做项目时,发现使用uiatuomator中遇到了一些问题,现在把解决方法和思路分享出来 案列1:使用命令去启动要运用的apk包 在做自动化时,需要通过命令去启动APK的包,我使用的是sdk中自 ...

  9. 【MINA】序列化和反序列化我们要考虑的问题

    概念 序列化:将java对象转换为字节序列的过程叫做序列化 反序列化:将字节对象转换为java对象的过程叫做反序列化 要解决的问题 1.序列化时间 2.反序列化时间 3.bytes大小 4.操作方便 ...

  10. 第二章 jQuery选择器

    选择器是行为与文档内容之间的纽带,其目的是能轻松的找到文档中的元素. jQuery中的选择器继承了CSS的风格.利用jQuery选择器,可以非常便捷快速地找出特定的DOM元素,然后给它们添加相应的行为 ...