extern "C"/C中如何调用C++

在C文件中调用C++代码---笔记 背景: 我们提供的so库中,代码是纯 c++ 代码,里面包含了cpp 的各种特性:类、虚函数等等。但是由于客户平台原因,他们使用的是纯 C 语言,也就是代码文件的后缀也是以 “.c” 结尾的。他们需要在 C 文件中调用我们库里面的 CPP 接口,在编译的时候,编译器一直报找不到接口。 第一次尝试: 通过在我们的 CPP 代码里面加 “extern c” 的方式,错误如故; 第二次尝试: 新创建一个... 阅读详情

extern "C"概述

被extern "C"修饰的变量和函数是按照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
#i nclude "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"通常的使用技巧。
(1)在C++中引用C语言中的函数和变量,在包含C语言头文件(假设为cExample.h)时,需进行下列处理:

extern "C"
{
#i nclude "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);
#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"
}
int main(int argc, char* argv[])
{
add(2,3);
return 0;
}

(注意这里如果用GCC编译的时候,请先使用gcc -c选项生成cExample.o,再使用g++ -o cppFile cppFile.cpp cExample.o才能生成预期的c++调用c函数的结果,否则,使用g++ -o cppFile cppFile.cpp cExample.c编译器会报错;而当cppFile.cpp 文件中不使用下列语句

extern "C"
{
#include "cExample.h"
}

而改用

#include "cExample.h"
extern "C" int add( int x, int y );

时g++ -o cppFile cppFile.cpp cExample.c的编译过程会把add函数按c++的方式解释为_foo_int_int这样的符号。
如果C++调用一个C语言编写的.DLL时,当包括.DLL的头文件或声明接口函数时,应加extern "C" { }。

 

( 2 ) C中调用C++

将 C++ 函数声明为``extern "C"''(在你的 C++ 代码里做这个声明),然后调用它(在你的 C 或者 C++ 代码里调用)。例如:

// C++ code:

extern "C" void f(int); 

void f(int i)

{

     // ...

} 

然后,你可以这样使用 f():

/* C code: */

void f(int); 

void cc(int i)

{

    f(i);

   /* ... */

}

当然,这招只适用于非成员函数。如果你想要在 C 里调用成员函数(包括虚函数),则需要提供一个简单的包装(wrapper)。例如:

// C++ code:
class C
{
       // ...
       virtual double f(int);
}; 

extern "C" double call_C_f(C* p, int i) // wrapper function
{
       return p->f(i);
}

然后,你就可以这样调用 C::f():

/* C code: */
double call_C_f(struct C* p, int i); 

void ccc(struct C* p, int i)
{
       double d = call_C_f(p,i);
       /* ... */
} 

如果你想在 C 里调用重载函数,则必须提供不同名字的包装,这样才能被 C 代码调用。例如:

// C++ code:
void f(int);
void f(double); 

extern "C" void f_i(int i) { f(i); }
extern "C" void f_d(double d) { f(d); } 

然后,你可以这样使用每个重载的 f():

/* C code: */
void f_i(int);
void f_d(double); 

void cccc(int i,double d)
{
       f_i(i);
       f_d(d);
       /* ... */
} 

注意,这些技巧也适用于在 C 里调用 C++ 类库,即使你不能(或者不想)修改 C++ 头文件。 

 

参考

[1] http://baike.baidu.com/view/2816461.htm?fromId=2814224 百度extern "C"

[2] http://www.cppblog.com/franksunny/archive/2007/11/29/37510.html C中如何调用C++

C++入门>>连接规范---extern “C“ 文章目录前言:背景内部名称修饰extern “C”C++项目调用C静态库C静态库的生成C++项目中C静态库的包含于配置、包含配置一配置二效果C项目调用C++库C++静态库的生成效果总结 前言: 本文介绍C++程序中的连接规范》》extern “C” 博主收集的资料New Young,连载中。 博主收录的问题:New Young 转载请标明出处:New Young 背景 在使用不同编程语言进行软件的开发时,需要统一变量,函数名等的链接规范。 如果C++项目中包含C静态库或者动 阅读详情

相关推荐

extern “C“ 怎么使用? 函数前加 extern 是什么意思? 深度理解 C++ 与 C 代码之间的互操作性

C++ 代码(library.cpp)C 语言代码(main.c)// main.c// 声明 C++ 函数return 0;编译和链接# 编译 C++ 代码 g++ -c library.cpp -o library.o # 编译 C 代码 gcc -c main.c -o main.o # 链接生成可执行文件 g++ main.o library.o -o my_program运行my_program用途extern "C"

Meet_Unknown的博客 1625

为什么需要 extern “C“ ?如何从C中调用C++函数

为什么需要 extern "C"? 假设我们有下面三个文件: // util.h int add(int, int); // util.c int add(int a, int b) { return a + b; } // main.c #include "util.h" int main(int argc, char *argv[]) { int sum = add(1, 2); return 0; } 使用 gcc 编译,生成的符号表内容分别是下面..

qq295109601的博客 719

C++中extern “C”深层探索

C++语言的创建初衷是“a better C”,但是这并不意味着C++中类似C语言的全局变量和函数所采用的编译和连接方式与C语言完全相同。作为一种欲与C兼容的语言,C++保留了一部分过程式语言的特点(被世人称为“不彻底地面向对象”),因而它可以定义不属于任何类的全局变量和函数。但是,C++毕竟是一种面向对象的程序设计语言,为了支持函数的重载,C++对全局函数的处理方式与C有明显的不同。C引用C++函数例子工程中包含的三个文件的源代码如下://C++头文件 cppExample.h#endif。

程序猿老樊的博客 854

在C中调用C++函数

使用extern "C"可以实现在C语言代码中调用C++函数的功能。实例分为5个文件:CallCpp.c CppPrint.cpp CppPrint.h CWrapper.cpp CWrapper.h其中CppPrint.cpp中是C++代码的实现;/* * CppPrint.h * */ #ifndef CPP_PRINT_H #define CPP_PRINT_H #include

daxiguacll的博客 3233

Allegro17.4原理图-PCB双向联动技巧:从网表生成到同步高亮

本文深入解析了Cadence Allegro 17.4中原理图与PCB的深度双向联动技巧。核心在于通过精准的网表生成与管理、实时的跨窗口交互高亮与信号追踪,以及元件与封装的智能匹配更新,构建高效协同设计工作流。掌握这些技巧能显著提升高速、高密度电路设计的效率与准确性,实现从逻辑设计到物理实现的无缝衔接。

weixin_29178069的博客 358

一文搞定学术英语写作 (斯坦福SCI论文写作课程笔记)

0.前言: 本文基于斯坦福Kristin Sainani 教授的学术论文写作公开课——SCI论文写作(Writing in the Sciences)。在此基础上进行章节顺序的重排及部分内容的删减,以方便第一次进行英语学术论文写作的同学快速上手。 时间充足和想要系统学习英文学术写作的同学,十分建议观看完整课程视频,一定会受益匪浅!课程地址如下: 课程B站地址:https://www.bilibili.com/video/BV1zv41177JQ 1.论...

Ogmx的博客 3万+

extern “ C “,实现C与C++项目的相互调用

extern "C"实现不同编程语言之间的相互调用

weixin_46016019的博客 2870

告别玄学:手把手配置EtherCAT从站PDI接口与同步采样(含Sync/Latch信号实战)

本文详细解析了EtherCAT从站PDI接口配置与同步采样技术,涵盖微处理器通信与直接驱动IO模式选择、同步采样四大触发模式(SOF、Latch_in、Sync0/Sync1)及输出触发实战。通过伺服驱动器实例,帮助工程师突破配置难点,实现高精度同步控制,提升工业自动化系统性能。

weixin_30667649的博客 483

extern “C“的作用:c语言调用c++代码中普通函数和类的方法教程(符xcode编译器演示demo)

目录前言extern "C"的作用利用extern "C"给c++ 函数做声明,然后再定义函数,让.c文件可以找到c++的函数c语言调用c++中的全局函数,这里不包含类的概念,直接用 前言 这篇教程主要讲解了,c语言,如何调用c++的类和类方法,目的是为了用swift调用c++代码的教程做铺垫,因为swift无法直接调动c++代码,但是可以调用c语言代码和oc代码,所以先做了这个教程.作为swift调用c++代码其中一种方法的铺垫教程 extern "C"的作用 首先这个 extern “C” {}是告诉

小手琴师的博客 2526

KEPServerEX 6 之 lot Gateway MQTT Clinet 配置使用方式

IoT Gateway即Internet of Things Gateway物联网网关。 ---------------------------------------------------------------------------------- 方式:使用kepw的IOTGateway插件选择MQTTClient 解决:可以实现 KEPW 的Tag值 发送到 MQTT 服务器上 ----------------------------------------...

-雲飛兄-博客 6942

lammps案例:扭转

扭转有两种方式,一是固定一端旋转另外一端,二是两端沿相反的方向旋转。案例为两侧旋转方式,扭转后的效果如图所示。

lammps_jiayou的博客 1199

c++中extern “C“的作用及理解

1 意图 extern "C"是C++特有的指令(C无法使用该指令),目的在于支持C++与C混合编程。 2 作用 extern “C”的作用是告诉C++编译器用C规则编译指定的代码(除函数重载外,extern “C”不影响C++其他特性)。 3 原因 为什么要用C规则编译C++代码呢? 因为C和C++的编译规则不一样,主要区别体现在编译期间生成函数符号的规则不一致。 C++比C出道晚,但是增加了很多优秀的功能,函数重载就是其中之一。由于C++需要支持重载,单纯的函数名无法区分出具体的函数,所以

米碎师兄 3万+

Android 12 系统横屏时,开机动画有两秒显示不全

平板系统默认横屏时,开机会旋转90度,显示的分辨率WxH,会变成HxW.但又会很快被SurfaceFlinger的SurfaceFlinger::processDisplayChanged 娇正。所以为了保险,可以在开机动画没结束之前,禁止旋转事件。在Android 12 产品定制化开发中,由于系统默认方向为竖屏,平板电脑要横屏显示。系统在开机时,有时因为旋转,会出现动画只显示一部分。

448313096@qq.com 1180

【C++】extern “C“ 和 extern 深度探索

本文介绍了C和C++中extern关键字的用法及其在链接阶段的作用。extern用于声明在其他文件中定义的全局变量或函数,实现跨文件共享。extern "C"则是C++特有的用法,用于指示编译器按照C语言的链接规则处理代码,解决C++与C语言的链接兼容性问题,避免名称修饰带来的链接错误。文章还探讨了extern在修饰const变量时的注意事项,以及extern "C"影响本文件符号导出的细节。此外,还讨论了extern "C"对普通类型和C++类型符号导出的影响,以及extern "C"的正确使用方式。

杨翔裕的博客 2122

图文详解Trae配置Java开发环境

本文介绍了Trae开发工具的安装配置流程:首先从官网下载安装Trae,然后安装Java开发所需的Extension Pack for Java和Spring Boot Extension Pack插件。关键步骤包括修改settings.json配置文件,需指定JDK路径、Maven可执行文件路径和用户设置文件路径。所有操作均配有图示说明,并强调要替换为实际电脑路径。

谷哥的小弟 5992

rk3588主板PDM接口接数字MIC录音

本文介绍了Rockchip 3588平台上6麦克风PDM接口的硬件连接与软件调试过程。硬件方面展示了PDM0_CLK0_M0时钟脚和三组数据脚的连接方案。软件配置包括设备树修改,生成声卡节点,并提供了6通道录音命令示例。文章重点分析了两个常见问题:录音无声(需检查供电、接线和波形)和通道数据缺失(需正确配置rockchip,path-map寄存器映射)。最后通过Audition工具验证录音文件,确认各通道工作正常。调试过程完整展现了从硬件连接到软件配置的完整流程。

m0_60805802的博客 1014

C++ extern “C”的作用详解

C++ extern “C”的作用详解1.示例2. 补充说明-C、C++编译器3. extern "C"使用要点 Reference: extern “C”的作用详解 extern "c" 的主要作用就是为了能够正确实现C++代码调用其他C语言代码。加上 extern “c” 后,会指示编译器这部分的代码按C语言,而不是C++的方式进行编译。 由于C++支持函数重载,因此编译器编译函数的过程中会将函数的参数类型也加到编译后的代码中,而不仅仅是函数名;而C语言并不支持函数重载,因此编译C语言代码的函数时

泠山的博客 1万+

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

C++ 中 extern 与 extern “C“ 详解:从跨文件共享到 C/C++ 混合编程

场景 | 说明 || 全局变量跨文件共享 | 一个文件定义,其他文件用extern声明引用 || 全局常量跨文件共享 | 定义时加上,声明时也用| 头文件中的全局变量声明 | 头文件中使用extern声明,在单个 .cpp 中定义 || 跨文件函数调用 | 通常通过头文件声明即可,不需要显式写extern// header.h (错误写法)// 这是定义,不是声明!#include "header.h" // 定义一次。

✨ 欢迎来到【Seal ^_^ 的优快云博客】!✨ 737

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

【C++】extern “C“详解

参考: extern “C“的作用及理解 extern C里面能有C++代码吗? 1. 概述 extern “C” 是C++特有的指令(C无法使用该指令),目的在于支持C++与C混合编程。 2. 作用 extern “C” 的作用是告诉C++编译器用C规则编译指定的代码(除函数重载外,extern “C” 不影响C++其他特性)。 3. 原因 为什么要用C规则编译C++代码呢? 因为C和C++的编译规则不一样,主要区别体现在编译期间生成函数符号的规则不一致。 C++比C出道晚,但是增加了很多优秀的功能,.

lemonxiaoxiao的博客 2139

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

【C++】extern “C“

extern “C” 1. C++调用C 程序不能调用程序,程序只能调用库 (静态库或动态库) 如果想要实现C++去调用C 创建工程,找到静态库 将.c文件的代码写完之后,运行程序,会生成.lib文件 注意:这里是静态库,不需要写main函数,因为不是运行程序 切换到 .cpp文件 一般调用库使用 #include #include "../." . 一个个点号表示当前文件 .. 两个点号表示当前文件的上一个文件 找到 .h文件,其实就是包含一个头文件,就是这个头文件可以不在当前目录或者

Rinne's blog 778

【C/C++ extern“C”的用法,及C++调用C,C调用的C++案例】

而C语言不支持函数重载,也不进行名字修饰,因此直接使用C++编译器编译的C代码(或C++代码中嵌入的C代码)在链接时可能会因为找不到正确的函数名而导致链接错误。在实际项目中,你会在C++代码中通过extern "C"声明C函数,然后在链接时包含C代码编译生成的目标文件(.o或.obj文件)。为了从C代码中调用cpp_function,你需要在C代码中声明这个函数为extern(尽管这不是必须的,因为extern "C"已经在C++代码中声明了),但重要的是确保链接器能找到C++代码编译生成的函数。

一起学习进步! 658

C++中如何调用C语言函数?extern “C“详解

在C++项目中调用C语言代码时,由于编译规则不同,需使用extern "C"避免链接错误。它告诉C++编译器以C语言方式处理函数名,确保正确调用。通过宏__cplusplus可实现跨语言兼容的头文件设计,方便混合编程。

weixin_34547628的博客 968

C++ | extern “C“

在 C++ 编程中,extern "C"是一个非常重要的特性,它主要用于解决 C++ 与 C 代码之间的相互调用问题。本文将深入探讨extern "C"的作用、使用原因以及具体的使用方法。

@ 1477

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

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

2501_93283929的博客 818

C/C++分享点:extern 与extern "C"

C/C++分享点:extern 与extern “C” 1.exern 的作用 1.1 引用同一个文件中的变量 看一段测试代码: #define _CRT_SECURE_NO_WARNING 1 #include<stdio.h> int func(); int main() { func(); printf("%d\n", num); return 0; } in...

lengji22的专栏 814
上一篇: TQ2440-U-BOOT-1.1.6启动流程及常用功能浅析
下一篇: C语言编译过程总结详解
forsakening
博客等级 码龄15年 83粉丝 72原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值