链接提示 extern "C"

2023-05-16

在 C++中调用 C 代码时,需要给编译器指定C代码要按照C语言的编译器编译,否则编译器会将C代码按照默认的C++编译器来编译C代码,这样在调用C代码时,会发生链接错误,找不到函数定义,因为C++编译器和C编译器对函数编译的过程都一点点区别。
下面先讲一下为什么会发送找不到函数定义的错误,进而弄清楚为什么需要extern “C” 来指定C编译器,然后再讲一个简单的例子说明如何使用 extern “C”。

C++编译器和C编译器

先来看一个简单的例子:

#include <iostream>

using namespace std;

void a(int i){
    cout<<"a1: "<<i<<endl;      
}

void a(int i, int j){
    cout<<"a2: "<<i<<" and "<<j<<endl;      
}

int main()
{
   a(1);
   a(2, 2);
   return 0;
}

使用 g++ -c -o mian.o main.cpp 编译,然后readelf -s main.o:

13: 0000000000000000    58 FUNC    GLOBAL DEFAULT    1 _Z1ai                                                               
14: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND _ZSt4cout                                                           
15: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND _ZStlsISt11char_traitsIcE                                           
16: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND _ZNS olsEi                                                      
17: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND _ZSt 4endlIcSt11char_trait                                       
18: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND _ZNS olsEPFRSoS_E                                                    
19: 000000000000003a    90 FUNC    GLOBAL DEFAULT    1 _Z1aii                                                              
20: 0000000000000094    36 FUNC    GLOBAL DEFAULT    1 main 
21: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND _ZNSt8ios_base4InitC1Ev                                             
22: 0000000000000000     0 NOTYPE  GLOBAL HIDDEN   UND __dso_handle                                                        
23: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND _ZNSt8ios_base4InitD1Ev                                             
24: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND __cxa_atexit                                        

主要看第13行和第19行的FUNC,C++中支持重载,实现的机制就是编译器对C++函数名进行一个处理,加上函数的参数类型,这样就可以唯一确定每一个C++函数了。比如这里C++编译器把 void a(int i) 函数名处理为 _Z1ai,把 void a(int i,int j) 函数名处理为 _Z1aii 。链接的时候通过 _Z1ai 和 _Z1aii 就可以找到对应的函数了。


然后我们再来看一个C例子:

#include <stdio.h>

void a(int i){
    printf("a1: %d\n", i);      
}

int main()
{
    a(1);
    return 0;
}

C语言不支持重载,所以只写了一个函数。同样,用gcc -c -o main.o main.c 编译,用readelf -s main.o查看:

0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND      
1: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS main.c                                                              
2: 0000000000000000     0 SECTION LOCAL  DEFAULT    1      
3: 0000000000000000     0 SECTION LOCAL  DEFAULT    3      
4: 0000000000000000     0 SECTION LOCAL  DEFAULT    4      
5: 0000000000000000     0 SECTION LOCAL  DEFAULT    5      
6: 0000000000000000     0 SECTION LOCAL  DEFAULT    7      
7: 0000000000000000     0 SECTION LOCAL  DEFAULT    8      
8: 0000000000000000     0 SECTION LOCAL  DEFAULT    6      
9: 0000000000000000    34 FUNC    GLOBAL DEFAULT    1 a    
10: 0000000000000000    0 NOTYPE  GLOBAL DEFAULT  UND printf                                                              
11: 0000000000000022   21 FUNC    GLOBAL DEFAULT    1 main 

可以看到第9行的FUNC的名字 a 跟代码中的函数名是一样的。C代码中,就是通过这个名字来寻找对应的函数实现。


好了,现在我们知道了C++ 和C编译器对函数名的处理方式不同了。正是由于这种区别,我们要通过使用extern “C”来告诉编译器这是C代码,要用C编译器。


C++头文件中使用extern “C”

需要注意的是,extern “C”是C++语法,所以只能在C++文件中使用。在C++代码中使用C函数,可以在C++头文件中对C函数的头文件使用 extern “C”声明。最常用的格式如下:

//C++ headfile
#ifdef __cplusplus 
extern "C" { 
#endif 

//一段C代码

#ifdef __cplusplus 
} 
#endif

下面举一个简单的例子来说明如何使用 extern “C”
4个文件,cprint.c,cprint.h 和 ccprint.cc ccprint.h。其中main函数在ccprint.cc中,并且调用cprint.c中的函数。

//cprint.h
#ifndef _CFUNCTION_H
#define _CFUNCTION_H

void CPrint( int num );

#endif
//cprint.c
#include "cfunction.h"
#include <stdio.h>


void CPrint( int num ) {
  printf( "C function: %d.\n", num );
}
//ccprint.h
#ifndef _CPPFUNCTION_H
#define _CPPFUNCTION_H

void CppPrint( int num );


#ifdef __cplusplus
extern "C"{
#endif

#include "cfunction.h"

#ifdef __cplusplus
}
#endif

#endif
//ccprint.cc
#include "ccfunction.h"
#include <iostream>

void CppPrint( int num ) {
  std::cout << "Cpp Print: " << num << std::endl;
}

int main() {
  CPrint( 20 );
  CppPrint( 10 );
  return 0;
}

这样就可以成功编译和运行啦

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

链接提示 extern "C" 的相关文章

随机推荐

  • slam相关文章

    1 视觉SLAM漫谈 http www cnblogs com gaoxiang12 p 3695962 html 2 学习SLAM需要哪些预备知识 xff1f https www zhihu com question 35186064 3
  • 工业机器人主要核心

    主要核心为三部分 xff0c 控制器 xff08 就是用来控制机器人动作的那个手持设备 xff0c 可以用来编程 xff0c 一般用vxworks和linux xff0c wince来实现 xff09 伺服电机和减速器用来实现机器人的动作
  • 想搞工业机器人 这五大方面你必须了解

    origin http www robot china com news 201510 09 25754 html 1 工业机器人控制系统硬件结构 控制器是 机器人 系统的核心 xff0c 国外有关公司对我国实行严密封锁 近年来随着微电子技
  • 为什么我选择并且推崇用ROS开发机器人?

    origin http www leiphone com news 201701 zBHXGJcsRTioj4gH html 雷锋网 公众号 xff1a 雷锋网 按 xff1a 本文来自知乎 xff0c 作者贾子枫 xff0c 雷锋网已获授
  • 一飞智控CEO齐俊桐:一篇文章教你看透无人机飞控这十年

    origin http www leiphone com news 201702 YO2bskI7smE1U8TA html 无人机 又一个被国人玩坏了的单词 科幻电影里的无人机 10年前说自己是搞无人机的 xff0c 无不引来疑惑和赞叹的
  • 机器人框架

    ROS Rock Yarp Orocos
  • 列王的纷争-深度传感器已被巨头瓜分?

    origin http mt sohu com 20170325 n484729546 shtml 我们常常说苹果富可敌国 但是你这么说其实是在侮辱苹果 苹果可比美国政府有钱多了 根据最新消息 xff0c 美国政府账上的现金 xff0c 只
  • 不得不看!国内深度摄像头方案大起底

    origin http pieeco baijia baidu com article 517947 引言 xff1a 市场对深度视觉技术需求趋于井喷 xff0c 但可以提供产品和方案的公司寥寥无几 xff0c 本文分析了国内三家各具特点的
  • VR中的9轴传感器(重力加速度/陀螺仪/磁力计)

    origin http blog csdn net dabenxiong666 article details 53836503 前言 传感器的调试过程 xff0c 一般根据原厂提供demo代码 xff0c 调试数据接口 xff0c 将数据
  • STM32中AD采样的三种方法分析

    在进行STM32F中AD采样的学习中 xff0c 我们知道AD采样的方法有多种 xff0c 按照逻辑程序处理有三种方式 xff0c 一种是查询模式 xff0c 一种是中断处理模式 xff0c 一种是DMA模式 三种方法按照处理复杂方法DMA
  • 神经网络:比原来更容易学习了

    origin http geek csdn net news detail 195039 原文 xff1a NEURAL NETWORKS YOU VE GOT IT SO EASY 作者 xff1a Steven Dufresne 翻译
  • NuttX 编译系统

    origin http blog csdn net zhumaill article details 24400441 xff08 嵌入式 实时操作系统 rtos nuttx 7 1 makefile xff09 NuttX 编译系统 转载
  • NuttX 启动流程

    origin http blog csdn net zhumaill article details 23261543 xff08 嵌入式 实时操作系统 rtos nuttx 7 1 stm32 源代码分析 xff09 NuttX 启动流程
  • nuttx操作系统的移植以及下载

    origin http blog csdn net seawolfe article details 70244672 1 在ubuntu根目录下 xff1a root 64 ubuntu apt get update 更新包 2 root
  • 机器人峰会厂商

    origin http www chinarobtop com exhibition exhibition php 埃夫特 清能德创 芜湖瑞思 芜湖哈特 山东帅克机械 宁波慈兴轴承 A6 成都卡诺普 绿的谐波
  • 机器人公司

    1 螺趣科技 2 米兔机器人 3 360
  • 解:高性能MEMS IMU解决方案-ADXRS290

    origin https ezchina analog com message 34890 对于复杂且高动态惯性配置的MEMS IMU应用 xff0c 评估功能时需要考虑许多属性 在设计周期早期评估这些属性优于追逐开放性成果 xff0c 从
  • 关于DIY电池均衡器--被动均衡---蓄电池--电瓶车电池组电压均衡的经历

    提示 xff1a 文章写完后 xff0c 目录可以自动生成 xff0c 如何生成可参考右边的帮助文档 前言 随着电动车长时间的反复使用 xff0c 电池参数难免会发生变化 xff0c 当电池组中各节电池参数不一时 xff0c 便会出现充电时
  • CMakeLists.txt与Makefile 的区别

    我平时一般是在windows使用VS编程 xff0c 但是偶尔在网上查资料的时候也会下载一些别人的代码 xff0c 其中就经常对CMakeLists txt和Makefile文件产生疑惑 xff0c 下面我来分析一下这两个经常使用的地方 C
  • 链接提示 extern "C"

    在 C 43 43 中调用 C 代码时 xff0c 需要给编译器指定 xff23 代码要按照 xff23 语言的编译器编译 xff0c 否则编译器会将 xff23 代码按照默认的C 43 43 编译器来编译 xff23 代码 xff0c 这