【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 ...
随机推荐
- 2019EC-Final参赛总结
本来想发知乎上的,后来发现太长就放这好了23333 没写过这种东西,所以写得比较混乱&流水账 以下内容均为我的个人视角XD 赛前 在车上的时候,红太阳跟我们说他头晕(虽然他好像每场比赛都头 ...
- BZOJ 3576: [Hnoi2014]江南乐 (SG函数)
题意 有nnn堆石子,给定FFF,每次操作可以把一堆石子数不小于FFF的石子平均分配成若干堆(堆数>1>1>1). 平均分配即指分出来的石子数中最大值减最小值不超过111.不能进行操 ...
- P4149 [IOI2011]Race 点分治
思路: 点分治 提交:5次 题解: 刚开始用排序+双指针写的,但是调了一晚上,总是有两个点过不了,第二天发现原因是排序时的\(cmp\)函数写错了:如果对于路径长度相同的,我们从小往大按边数排序,当双 ...
- BigDecimal 3个toString()方法区别
BigDecimal 的toEngineeringString.toPlainString和toString方法的区别: toEngineeringString:有必要时使用工程计数法.工程记数法是一 ...
- 二进制学习——Blob,ArrayBuffer、File、FileReader和FormData的区别
前言: Blob.ArrayBuffer.File.fileReader.formData这些名词总是经常看到,知道一点又好像不知道,像是同一个东西好像又不是,总是模模糊糊,最近终于下决心要弄清楚. ...
- MySQL实现计算两点之间的距离
DELIMITER $$ CREATE FUNCTION `calculateLineDistance`(startLng double, startLat double, endLng double ...
- openstack 本地导入镜像.
网络很慢,直接本地传. openstack image create "Fedora30" --file Fedora-Cloud-Base-30-1.2.x86_64.qcow2 ...
- psexec局域网执行远程命令
执行远程命令的工具psexec.exe 下载 一.首先,被控制机器必须开启ipc$,以及admin$,否则无法执行 开启ipc$ net share IPC$ 开启admin$ net share A ...
- Win10配置Java环境变量
很多同学在学习Java入门的时候被Java环境变量搞的一头雾水,今天这篇文章拓薪教育就来说一下如何在win10下配置环境变量; 下载jdk安装包: 首先我们需要下载jdk的安装包,这里提供jdk的安装 ...
- linux中如何修改最大文件句柄数
1.使用ulimit -a可以查看,其中的open files后面的数就是最大文件句柄数 2.临时方法:使用ulimit -n size修改最大文件句柄数(这种方法只针对当前进程有效) 3.永久方法: ...