【VS开发】MFC中调用C函数模块的解决方案
【VS开发】MFC中调用C函数模块的解决方案
标签(空格分隔): 【VS开发】
声明:引用请注明出处http://blog.csdn.net/lg1259156776/
说明:最近调试基于MFC的程序,当通过外部C文件引入某个function的时候,又一次忘记了C文件与C++文件的区别,直接按照一般的方式,将函数声明放入头文件,将函数定义放入C文件,然后再MFC中通过包含头文件来引用对应的function,然而爆出了链接时无法定位的错误,本文就来梳理一下C++中调用C中功能函数的方法。
首先在C文件中,.c中是不允许出现任何形式的C++调用的,所以别指望C中去调用C++文件中定义的功能函数(除非使用extern “C”告诉编译器依照C的方式来编译封装接口,因为在编译生成的目标文件中,以相同的函数名为例:int foo( float x ),C接口的函数导出符号为foo与C++接口的函数导出符号_foo_float不同,因为C++编译器为了实现函数重载,会在编译时带上函数的参数信息,所以不提前声明是不能调用的,还记不记得前段时间读过的程序员的自我修养总结中的例子,我只是有点遗忘罢了。关于C中调用C++的函数,见下一个篇文章)。然后反过来,因为C++是后继的,可以包容C,所以在C++语法中有声明函数为C代码段的规定,这里说明一下几种方法:
1. 链接报错
Test.obj : error LNK2019: 无法解析的外部符号 “void __cdecl DeleteStack(struct _Node *)” (? DeleteStack@@YAXPAU_Node@@@Z),该符号在函数 _main 中被引用。
2. method 1
#ifdef __cplusplus
extern “C”
#endif
void DeleteStack(Stack stack);
如果是在C++编译器下,自动定义一个_cplusplus宏,使用extern “C”来修饰,表示外部接口函数为C的规范。当然还可以用大括号,表示集体修饰:
#ifdef __cplusplus
extern "C" {
#endif
void DeleteStack(Stack stack);
void PrintStack(Stack stack);
void Pop(Stack stack);
#ifdef __cplusplus
}
#endif
3. method 2
直接按照头文件,源文件的格式编写,直接声明整个头文件为C规范:
// CStack.h
extern "C" {
#include "Stack.h";
}
代码参考于《C++调用C函数》
源文件在编译器下生成的目标文件中导出符号的规则问题
另外,具体的关于源文件在编译器下生成的目标文件中导出符号的规则问题,可以参看我的另一篇博文《【读书笔记】程序员的自我修养总结(三)》,具体的内容我粘贴如下:
由于全局符号在链接过程是全局可见的,所以如果编写的库文件中和当前的目标文件中有相同的符号名,那么就会发生冲突。为了防止类似的符号名冲突,UNIX下的C语言规定,C语言源代码文件中的所有全局变量和函数经过编译以后,相对应的符号名前面加上下划线,“_”。但如果是一个大型的软件,由不同的部门来开发,他们之间的命名规范如果不严格,则可能导致冲突,于是C++这样的语言使用了Namespace来解决不同模块下的符号冲突。
C++的符号修饰机制指的是C++语言支持不同参数类型的函数拥有一样的名字,即函数重载。实际上他们在编译的时候会进行一个函数签名,包含函数名,参数类型,所在类和命名空间等信息。
而名称修饰机制,也被用来防止静态变量,不同的编译器可能名称修饰方法不同,函数签名可能对应不同的修饰名称,由于不同的编译器采用不同的名字修饰方法,必然导致由不同编译器编译产生的目标文件无法正常相互链接。
“extern C”用法
C++中为了与C兼容,在符号管理上有一个用来声明或定义一个C的符号的“extern C”关键字用法:
extern “C”{
int func(int);
int var;
}
C++ 编译器会将extern “C”的大括号内部的代码当作C语言来处理。VC++平台会将C语言的符号进行修饰,即大括号中的func和var修饰后的符号为_func和_var,而C++部分的则按照C++的那一套进行修饰。
而下面的一段代码常常用来解决C/C++两种源码编译形式:
#ifdef __cplusplus
extern "C"{
#endif
void *memset(void *, int, size_t);
#ifdef __cplusplus
}
#endif
如果当前参与编译的是C++代码,memset会在extern “C”中被声明,按照C代码进行符号修饰;而如果是C代码,直接声明即可。(C语言不支持extern “C”,而__cplusplus这个宏是C++编译器默认定义的,如果是C++编译器参与的编译,则就默认定义了该宏。)。这段代码几乎在所有的系统头文件中都被利用。
2015-12-04 调试记录 张朋艺
【VS开发】MFC中调用C函数模块的解决方案的更多相关文章
- 如何给ioloop.run_sync()中调用的函数传入参数
问题 如何给tornado.ioloop.IOLoop中的run_sync方法中调用的函数添加参数 解决方案 使用functools.partial 解决示例 from tornado import ...
- [转]用多线程方法实现在MFC/WIN32中调用OpenGL函数并创建OpenGL窗口
原文链接: 1.用多线程方法实现在MFC/WIN32中调用OpenGL函数并创建OpenGL窗口 2.Windows MFC 两个OpenGL窗口显示与线程RC问题
- 【VS开发】【CUDA开发】如何在MFC中调用CUDA
如何在MFC中调用CUDA 有时候,我们需要在比较大的项目中调用CUDA,这就涉及到MFC+CUDA的环境配置问题,以矩阵相乘为例,在MFC中调用CUDA程序.我们参考罗振东iylzd@163.com ...
- 在C#中调用Win32函数EnumWindows枚举所有窗口。
原文 http://www.cnblogs.com/mfm11111/archive/2009/06/30/1514322.html 开发旺旺群发软件,难点及重要技术点分析(一) 一. ...
- lua中调用C++函数
lua中调用C++函数 我们产品中提供了很多lua-C API给用户在lua中调用,之前一直没用深究其实现原理,只是根据已有的代码在编码.显然这不是一个好的习惯,没用达到知其所以然的目的. 一.基本原 ...
- EC笔记,第二部分:9.不在构造、析构函数中调用虚函数
9.不在构造.析构函数中调用虚函数 1.在构造函数和析构函数中调用虚函数会产生什么结果呢? #; } 上述程序会产生什么样的输出呢? 你一定会以为会输出: cls2 make cls2 delete ...
- 关于在C#中构造函数中调用虚函数的问题
在C#中如果存在类的继承关系,应避免在构造函数中调用虚函数.这是由于C#的运行机制造成的,原因如下: 新建一个类实例时,C#会先初始化该类(对类变量赋值,并将函数记在函数表中),然后再初始化父类.构造 ...
- 如何在C语言中调用Swift函数
在Apple官方的<Using Swift with Cocoa and Objectgive-C>一书中详细地介绍了如何在Objective-C中使用Swift的类以及如何在Swift中 ...
- C中调用Lua函数
我们先来看一个简单的例子: lua_State* L = NULL; // 内部调用lua函数 double f(double x, double y) { double z; lua_getglob ...
随机推荐
- BZOJ 2229 / Luogu P3329 [ZJOI2011]最小割 (分治最小割板题)
题面 求所有点对的最小割中<=c的数量 分析 分治最小割板题 首先,注意这样一个事实:如果(X,Y)是某个s1-t1最小割,(Z,W)是某个s2-t2最小割,那么X∩Z.X∩W.Y∩Z.Y∩W这 ...
- Google-Guava Concurrent包里的Service框架浅析
原文地址 译文地址 译者:何一昕 校对:方腾飞 概述 Guava包里的Service接口用于封装一个服务对象的运行状态.包括start和stop等方法.例如web服务器,RPC服务器.计时器等可以实 ...
- .Net Core 过滤器
请求: public class MyRequest { [Required(ErrorMessage = "Name参数不能为空")]//Required 验证这个参数不能为空 ...
- Python 10.1.1
- Flutter布局2--Align
Align控件即对齐控件,能将子控件所指定方式对齐,并根据子控件的大小调整自己的大小. eg: 文字组件对齐于右下方 new Align( alignment: FractionalOffset.bo ...
- Visual Studio Code:使用技巧汇总
造冰箱的大熊猫@cnblogs 2019/8/9(最后更新2019/8/11) 试用了下微软出的Visual Studio Code,哎呀,有点小惊喜 将VSC的快捷键小结一下,不定期更新 功能 快捷 ...
- xgzc— math 专题训练(一)
Lucas定理 当\(p\)是质数时,有\((^n_m)\equiv(^{n/p}_{m/p}) * (^{n\%p}_{m\%p}) \pmod{p}\) 狄利克雷卷积 定义:\((f*g)(n)= ...
- 解决tomcat7控制台中文乱码问题
控制台启动会有乱码,找了很多方法都不行,最后找到一个可用的方法,非常简单 打开tomcat/conf/logging.properties找到java.util.logging.ConsoleHand ...
- 调皮捣蛋的Linux下有趣终端的合集
*本文作者:国光,转载自 FreeBuf.COM,原文地址:https://www.freebuf.com/news/144050.html 前言 刚开始接触Linux的我们,肯定认为Linux系统就 ...
- Sign APK without putting keystore info in build.gradle
http://stackoverflow.com/questions/20562189/sign-apk-without-putting-keystore-info-in-build-gradle/2 ...