extern "C"的用法解析

C/C++混合编程的桥梁:extern与extern“C“的实战解析与最佳实践 本文深入解析了C/C++混合编程中extern与extern"C"的关键作用与最佳实践。通过实战案例展示了如何避免链接错误、正确处理名称修饰问题,并提供了头文件组织、动态库交互等场景的解决方案,帮助开发者高效实现跨语言模块协作。 阅读详情
1.引言
   C++ 语言的创建初衷是 “a better C” ,但是这并不意味着 C++ 中类似 C 语言的全局变量和函数所采用的编译和连接方式与 C 语言完全相同。作为一种欲与 C 兼容的语言,
C++ 保留了一部分过程式语言的特点(被世人称为 “ 不彻底地面向对象 ” ),因而它可以定义不属于任何类的全局变量和函数。但是, C++ 毕竟是一种面向对象的程序设计语言
,为了支持函数的重载, C++ 对全局函数的处理方式与 C 有明显的不同。
 
2.从标准头文件说起
  某企业曾经给出如下的一道面试题:
  面试题
  为什么标准头文件都有类似以下的结构?
    #ifndef __INCvxWorksh
    #define __INCvxWorksh
    #ifdef __cplusplus
    extern "C" {
    #endif
    /*...*/
    #ifdef __cplusplus
    }
    #endif
    #endif /* __INCvxWorksh */
  分析
  显然,头文件中的编译宏 “#ifndef __INCvxWorksh 、 #define __INCvxWorksh 、 #endif”  的作用是防止该头文件被重复引用。
  那么
#ifdef __cplusplus
extern "C" {
  #endif
  #ifdef __cplusplus
}
#endif
  的作用又是什么呢?我们将在下文一一道来。
 
3.深层揭密extern "C"
   extern "C"  包含双重含义,从字面上即可得到:首先,被它修饰的目标是 “extern” 的;其次,被它修饰的目标是 “C” 的。让我们来详细解读这两重含义。
  被 extern "C" 限定的函数或变量是 extern 类型的;
   extern 是 C/C++ 语言中表明函数和全局变量作用范围(可见性)的关键字,该关键字告诉编译器,其声明的函数和变量可以在本模块或其它模块中使用。记住,下列语句:
   extern int a;
  仅仅是一个变量的声明,其并不是在定义变量 a ,并未为 a 分配内存空间。变量 a 在所有模块中作为一种全局变量只能被定义一次,否则会出现连接错误。
  通常,在模块的头文件中对本模块提供给其它模块引用的函数和全局变量以关键字 extern 声明 。例如,如果模块 B 欲引用该模块 A 中定义的全局变量和函数时只需包含模块 A 的头文件即可。这样,模块 B 中调用模块 A 中的函数时,在编译阶段,模块 B 虽然找不到该函数,但是并不会报错;它会在连接阶段中从模块 A 编译生成的目标代码中找到此函数。
  与 extern 对应的关键字是 static ,被它修饰的全局变量和函数只能在本模块中使用。因此,一个函数或变量只可能被本模块使用时,其不可能被 extern “C” 修饰。
  被 extern "C" 修饰的变量和函数是按照 C 语言方式编译和连接的;
  未加 extern “C” 声明时的编译方式
  首先看看 C++ 中对类似 C 的函数是怎样编译的。
  作为一种面向对象的语言, C++ 支持函数重载,而过程式语言 C 则不支持。函数被 C++ 编译后在符号库中的名字与 C 语言的不同。例如,假设某个函数的原型为:
void foo( int x, int y );
  该函数被 C 编译器编译后在符号库中的名字为 _foo ,而 C++ 编译器则会产生像 _foo_int_int 之类的名字(不同的编译器可能生成的名字不同,但是都采用了相同的机制,生成的新名字称为 “mangled name” )。
   _foo_int_int 这样的名字包含了函数名、函数参数数量及类型信息, C++ 就是靠这种机制来实现函数重载的。例如,在 C++ 中,函数 void foo( int x, int y ) 与 void foo( int x, float y ) 编译生成的符号是不相同的,后者为 _foo_int_float 。
  同样地, C++ 中的变量除支持局部变量外,还支持类成员变量和全局变量。用户所编写程序的类成员变量可能与全局变量同名,我们以 "." 来区分。而本质上,编译器在进行编译时,与函数的处理相似,也为类中的变量取了一个独一无二的名字,这个名字与用户程序中同名的全局变量名字不同。
  未加 extern "C" 声明时的连接方式
  假设在 C++ 中,模块 A 的头文件如下:
//  模块 A 头文件  moduleA.h
#ifndef MODULE_A_H
#define MODULE_A_H
int foo( int x, int y );
#endif
  在模块 B 中引用该函数:
//  模块 B 实现文件  moduleB.cpp
#include "moduleA.h"
foo(2,3);
  实际上,在连接阶段,连接器会从模块 A 生成的目标文件 moduleA.obj 中寻找 _foo_int_int 这样的符号!
  加 extern "C" 声明后的编译和连接方式
  加 extern "C" 声明后,模块 A 的头文件变为:
//  模块 A 头文件  moduleA.h
#ifndef MODULE_A_H
#define MODULE_A_H
extern "C" int foo( int x, int y );
#endif
  在模块 B 的实现文件中仍然调用 foo( 2,3 ) ,其结果是:
  ( 1 )模块 A 编译生成 foo 的目标代码时,没有对其名字进行特殊处理,采用了 C 语言的方式;
  ( 2 )连接器在为模块 B 的目标代码寻找 foo(2,3) 调用时,寻找的是未经修改的符号名 _foo 。
  如果在模块 A 中函数声明了 foo 为 extern "C" 类型,而模块 B 中包含的是 extern int foo( int x, int y )  ,则模块 B 找不到模块 A 中的函数;反之亦然。
  所以,可以用一句话概括 extern “C” 这个声明的真实目的(任何语言中的任何语法特性的诞生都不是随意而为的,来源于真实世界的需求驱动。我们在思考问题时,不能只停留在这个语言是怎么做的,还要问一问它为什么要这么做,动机是什么,这样我们可以更深入地理解许多问题):
  实现 C++ 与 C 及其它语言的混合编程。
明白了 C++ 中 extern "C" 的设立动机,我们下面来具体分析 extern "C" 通常的使用技巧。
 
   4.extern "C"的惯用法
  ( 1 )在 C++ 中引用 C 语言中的函数和变量,在包含 C 语言头文件(假设为 cExample.h )时,需进行下列处理:
extern "C"
{
#include "cExample.h"
}
  而在 C 语言的头文件中,对其外部函数只能指定为 extern 类型, C 语言中不支持 extern "C" 声明,在 .c 文件中包含了 extern "C" 时会出现编译语法错误 。
  笔者编写的 C++ 引用 C 函数例子工程中包含的三个文件的源代码如下:
/* c 语言头文件: cExample.h */
#ifndef C_EXAMPLE_H
#define C_EXAMPLE_H
extern int add(int x,int y);     //注:写成extern "C" int add(int , int ); 也可以
#endif
/* c 语言实现文件: cExample.c */
#include "cExample.h"
int add( int x, int y )
{
  return x + y;
}
// c++ 实现文件,调用 add : cppFile.cpp
extern "C"
{
  #include "cExample.h"        //注:此处不妥,如果这样编译通不过,换成 extern "C" int add(int , int ); 可以通过
}
int main(int argc, char* argv[])
{
  add(2,3);
  return 0;
}
  如果 C++ 调用一个 C 语言编写的 .DLL 时,当包括 .DLL 的头文件或声明接口函数时,应加 extern "C" {   } 。
  ( 2 )在 C 中引用 C++ 语言中的函数和变量时, C++ 的头文件需添加 extern "C" ,但是在 C 语言中不能直接引用声明了 extern "C" 的该头文件,应该仅将 C 文件中将 C++ 中定义的 extern "C" 函数声明为 extern 类型。
  笔者编写的 C 引用 C++ 函数例子工程中包含的三个文件的源代码如下:
//C++ 头文件  cppExample.h
#ifndef CPP_EXAMPLE_H
#define CPP_EXAMPLE_H
extern "C" int add( int x, int y );
#endif
//C++ 实现文件  cppExample.cpp
#include "cppExample.h"
int add( int x, int y )
{
  return x + y;
}
/* C 实现文件  cFile.c
/*  这样会编译出错: #include "cExample.h" */
extern int add( int x, int y );
int main( int argc, char* argv[] )
{
  add( 2, 3 );
  return 0;
}
  如果深入理解了第 3 节中所阐述的 extern "C" 在编译和连接阶段发挥的作用,就能真正理解本节所阐述的从 C++ 引用 C 函数和 C 引用 C++ 函数的惯用法。对第 4 节给出的示例代码,需要特别留意各个细节。

==============================================================================
我喜欢程序员,他们单纯、固执、容易体会到成就感;面对压力,能够挑灯夜战不眠不休;面对困难,能够迎难而上挑战自我。他们也会感到困惑与傍徨,但每个程序员的心中都有一个比尔盖茨或是乔布斯的梦想“用智慧开创属于自己的事业”。我想说的是,其实我是一个程序员。
==============================================================================

【C++基础】面试高频考点解析:extern “C“ 的链接陷阱与真题实战 掌握extern "C"的核心在于理解 C/C++ 链接规范差异,避免名字改编、头文件嵌套等陷阱。通过真题实战强化记忆,可有效应对面试中的各类问题。  阅读详情

相关推荐

解密微信DAT图片:一键转换JPG/PNG/GIF的实用指南

本文详细解析微信DAT图片的加密机制及转换方法,提供从定位文件到使用WeijieSoft工具一键转换JPG/PNG/GIF的完整指南。涵盖新旧版微信存储路径差异、批量处理技巧及常见问题解决方案,帮助用户高效恢复重要图片并释放存储空间。

weixin_29305337的博客 3614

extern “C“ 的使用

最近刚换了工作,刚进新公司几天,领导就给安排了一项任务:把项目里的c源文件改成cpp源文件,同时解决编译问题。修改文件扩展名虽容易,但会遇到各种问题,其中一个就是:undefined refrence to xxx,即未找到某某函数的实现。 出问题的原因是原来都是c实现的,在要使用的地方,直接extern+函数原型 声明即可。若此函数是c++实现的,也可以这样使用,但若函数是c实现的,在使用的地方再用extern+函数原型 声明则会找不到函数符号。解决办法就是添加上如: ...

tianyexing2008的博客 846

STM32 HAL库串口DMA接收不定长数据的两种实战方法:IDLE中断与超时管理详解

本文详细解析了STM32 HAL库中串口DMA接收不定长数据的两种实战方法:IDLE中断与超时管理。通过对比分析两种方案的硬件要求、响应速度和适用场景,为嵌入式开发者提供了高效可靠的串口通信解决方案,特别适用于智能家居、传感器网络等需要处理不定长数据包的应用场景。

weixin_30954265的博客 471

深入理解extern "C"

在用C/C++的项目源码中,经常会看到下面结构的代码: #ifdef __cplusplus extern "C" { #endif /*...*/ #ifdef __cplusplus } #endif这段代码到底有什么用呢,你知道吗?而且这样的问题经常出现在面试/笔试中。下面我就深入介绍下它: 1. #ifdef _cplusplus/#endif _cplusplus

Enjoy Coding 729

软件项目质量管理

识别项目中涉及质量管理的不同角色,如项目经理、质量经理、测试人员等,明确每个角色的职责和任务,包括负责哪些质量管理活动和决策。1、编制软件项目的质量管理计划,包括确定项目的质量标准和要求,以及制定质量控制和质量保证策略等。2、编制软件项目的质量管理计划,包括确定项目的质量标准和要求,以及制定质量控制和质量保证策略等。测试用例表是质量控制过程中的关键工具,确保所有功能和场景都被验证,减少项目中的缺陷。1、理解项目质量管理的基本过程,包括质量计划、质量保证、质量控制和质量改进;明确质量管理活动中的角色和职责。

weixin_51996255的博客 1258

深度学习中的注意力机制

最近两年,注意力模型(Attention Model)被广泛使用在自然语言处理、图像识别及语音识别等各种不同类型的深度学习任务中,是深度学习技术中最值得关注与深入了解的核心技术之一。本文以机器翻译为例,深入浅出地介绍了深度学习中注意力机制的原理及关键计算机制,同时也抽象出其本质思想,并介绍了注意力模型在图像及语音等领域的典型应用场景。

优快云人工智能 4万+

extern "C"的功能和用法研究

                                          上述代码段中:__cplusplus是一个C++规范规定的预定义宏;现代C++编译器都预先定义了它,而所有的C语言编译器则不会; 【注】:按照规范__cplusplus的值应该等于199711L,然而并不是所有的编译器都照此规范,比如g++编译器下__cplusplus的值为1。 上述代码段,如果再C编译器下...

SSS_369 2037

PyCharm+QT Designer整合

CMD下使用pip安装PyQt4或者PYQT5 这里要注意,你下载的PYQT5不包含QT designer 还要:pip3 install PyQt5-tools,好像Pyqt5中将designer分离了或者查看源码:https://github.com/altendky/pyqt5-tools,编译安装 将QT Designer整合到PyCharm的External Tools中,以后就可...

mxh的博客 6414

extern "C" __stdcall对函数的使用声明

extern "C" __stdcall对函数的使用声明如下: 1 extern "C": 在当调用别人写的库时,注意库是使用何种编译器,若是C的,则你在用VC中的C++编译器调用时就得加 #if defined(__cplusplus) extern "C" { #endif ..........声明被调用的函数名

slj_win的专栏 2773

亚马逊SP-API授权实战:从OAuth流程到Refresh Token获取

本文详细解析了亚马逊SP-API授权流程,从OAuth认证到Refresh Token获取的全过程。通过实战经验分享,帮助开发者快速掌握Marketplace Appstore、Website Workflow和自行授权三种方式,解决常见错误如MD5100和MD9999,并提供了安全存储Refresh Token的最佳实践。

weixin_30379531的博客 518

STM32 TIM3硬件XOR+复位模式实现霍尔信号精准捕获

霍尔传感器是电机控制系统中获取转子位置的关键器件,其三路数字信号需通过高精度、低延迟的边沿检测机制转换为电角度信息。其核心原理在于利用定时器输入XOR逻辑合并多路信号,并结合从模式复位(Reset Mode)实现硬件级时间间隔测量——每次跳变强制计数器清零,使CNT值直接表征换相周期。该方案规避了软件轮询的不确定性,显著提升FOC控制的实时性与鲁棒性。典型应用场景包括BLDC/FOC电机驱动、机器人关节伺服及工业变频器设计,尤其适用于STM32F4系列等具备硬件XOR与从模式控制器的MCU平台。

weixin_28931507的博客 91

DLL编写中extern “C”和__stdcall的作用

动态链接库的使用有两种方式,一种是显式调用。一种是隐式调用。 (1)       显式调用:使用LoadLibrary载入动态链接库、使用GetProcAddress获取某函数地址。 (2)       隐式调用:可以使用#pragma comment(lib, “XX.lib”)的方式,也可以直接将XX.lib加入到工程中。   DLL的编写 编写dll时,有个重要

koln频道 2万+

YOLOv9改进策略目录 | 包含卷积、主干、检测头、注意力机制、Neck上百种创新机制

Hello,各位读者们好本专栏自开设两个月以来已经更新改进教程50余篇其中包含RepNCSPELAN4、主干、检测头、注意力机制、Neck多种结构上创新,也有损失函数和一些细节点上的创新。同时本人一些讲解视频和包含我所有创新的YOLOv9文档并不能在优快云上传(所有的创新点都经过我的测试是可用的,得到该文件之后大家可以随意组合使用),所以会建立群的形式在内上传我的文件和视频我也会在群内不定期和大家交流回答大家问题,同时定期会更新一些文章的创新点(经过我融合测试后的,先到先得)。

Snu77的博客 1万+

C++调用C函数,为什么要加extern “C“?链接器视角完全解析

写C++库时,如果可能被C调用,导出的接口都加extern "C"参数和返回值用C兼容类型内部实现随便用C++特性遇到undefined reference错误,检查是否是C/C++混用问题用nm工具查看符号表确认符号名是否匹配写头文件时,用条件编译保证C/C++兼容#endif// 声明#endif理解链接器的工作原理,很多"神秘"错误就不神秘了编译和链接是两个阶段链接器只看符号表。

2501_93283929的博客 818

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

extern “C“的用法解析

转自:https://www.cnblogs.com/rollenholt/archive/2012/03/20/2409046.html 如涉及作品版权问题,请联系我进行删除。 文章目录1.引言2.从标准头文件说起3.深层揭密extern "C"4.extern "C"的惯用法 1.引言 C++语言的创建初衷是“a better C”,但是这并不意味着C++中类似C语言的全局变量和函数所采用的编译和连接方式与C语言完全相同。作为一种欲与C兼容的语言, C++保留了一部分过程式语言的特点(被世人称为“不彻底

肥宅快乐博客 278

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

【C与C++混合编程核心技术】:深入解析extern “C“的底层机制与实战应用

掌握C 语言与 C++ 的 extern "C" 兼容技术,解决混合编程中的符号链接难题。详解函数声明、头文件封装及编译器处理机制,实现C++调用C代码无缝对接。跨语言开发关键方案,值得收藏。

CompiGlow的博客 1011

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

C++项目中的extern “C“ {} 解析

引言 在用C++的项目源码中,经常会不可避免的会看到下面的代码: #ifdef __cplusplus extern"C"{ #endif /*...*/ #ifdef __cplusplus } #endif 1、#ifdef _cplusplus/#endif _cplusplus及发散它到底有什么用呢,你知道吗?而且这样的问题经常会出现在面试or笔试中。下面我就从以下几个方面来介绍它: 2、extern "C" 2.1、extern关键字 2.2、"C" 2.3、小结..

qq_36075612的博客 91

extern "C"的简单解析

原文地址https://www.cnblogs.com/houkai/archive/2013/06/05/3118807.html 作者:@houkai 本文为作者原创,转载请注明出处:https://www.cnblogs.com/houkai/archive/2013/06/05/3118807.html 1.揭密extern "C" extern "C"包含双重含义,从字面上即可得到...

qq_38415161的博客 294

extern "c"用法解析

引言 C++保留了一部分过程式语言的特点,因而它可以定义不属于任何类的全局变量和函数。但是,C++毕竟是一种面向对象的程序设计语言,为了支持函数的重载,C++对全局函数的处理方式与C有明显的不同。 extern “C”的主要作用就是为了能够正确实现C++代码调用其他C语言代码。加上extern”C”后,会指示编译器这部分代码按C语言的进行编译,而不是C++的。由于C++支持函数重载,因此编译器编

wonder 1万+

CUDA编程中 extern "c"用法解析

简介  extern “c”并不是什么新鲜的东西,但是最在编译CUDA程序时候出现了“error LNK2019,未定义的符号”的问题。这不用说了,链接器说找不到,那就是找不到咯。但是why?我的源码中明明已经有了定义。 后来发现是extern “c”的问题。extern “C”  C++保留了一部分过程式语言的特点,因而它可以定义不属于任何类的全局变量和函数。但是,C++毕竟是一种面向对象的程序

Zhang Junior 的博客 5955

extern "C"的解析

看了觉得挺好,先留着,转载的被遗忘的博客 extern “C”使用说明

qq_19288615的专栏 288

extern ”c”解析

extern "C" 包含双重含义,从字面上即可得到:首先,被它修饰的目标是“extern”的;其次,被它修饰的目标是“C”的。让我们来详细解读这两重含义。   (1) 被extern "C"限定的函数或变量是extern类型的   extern是C/C++语言中表明函数和全局变量作用范围(可见性)的关键字,该关键字告诉编译器,其声明的函数和变量可以在本模块或其它模块中使用。记住,下列

7543

ZT extern "C"的用法解析

extern "C"的用法解析 1.引言   C++语言的创建初衷是“a better C”,但是这并不意味着C++中类似C语言的全局变量和函数所采用的编译和连接方式与C语言完全相同。作为一种欲与C兼容的语言, C++保留了一部分过程式语言的特点(被世人称为“不彻底地面向对象”),因而它可以定义不属于任何类的全局变量和函数。但是,C++毕竟是一种面向对象的程序设计语言 ,为了支持函数的...

weixin_30607029的博客 118
上一篇: C++的输出精度控制(转)
下一篇: 一道经典概率问题
静水若流深
博客等级 码龄14年 5粉丝 12原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值