C++调用C函数用cmake编译时的一个诡吊链接错误

项目中需要用到C++程序调用一个在.c文件中实现的c函数,我按照网上给的方法,用extern声明,但老是链接错误。把问题简单化到很小查了半天,仍然不知为什么编译都正常,就是链接不上那个在.c文件中实现的函数。

而且最为诡吊的是,当我把函数名改变后,又能链接成功了。后来经过调试,发现这次链接成功居然又是伪成功,因为它链接到的是一个不知道什么鬼的库函数,而不是我实现的那个函数。也就是说,看上去是链接成功了,但实际上并非如此。我下面的用法其实是参考了https://blog.csdn.net/this_is_me_anyway/article/details/79397018的例子,特殊之处在于我这里是用到了一个模板类和模板函数。

针对这个问题,我最终的发现可总结为如下:

1. 使用cmake+make编译链接和使用g++(或gcc)分别编译再链接是有区别的

2. cfun()是一个库函数(虽然我也没搞清楚这个函数是在哪),但在我的例子中,这个不应该被调用的函数却在我的用户代码中被不经意地调用了。这造成了程序已经正确链接我自己实现的cfun()函数的假象。这个库函数的错误引入可能与cmake中编译器的使用有关(关于这一点我不太确定也一直很困惑)

简言之,我把问题抽象为如下很简单的例子:

在main.cc中,include一个fuck头文件,该头文件中声明并实现了一个Fuck类:

#include "fuck.h"
int main(){
   Fuck<2> fk;
   fk.print_fuck(3);
}

在fuck.h头文件中,是这样实现Fuck类的:

#ifndef __MS_H__
#define __MS_H__

#include "fun.h"

template<int dim>
class Fuck                      //这个Fuck类是个模板类
{
public:
   template<typename number>
   static
   void print_fuck(number x);   //定义了一个静态的模板成员函数
};

template<int dim>
template<typename number>
void Fuck<dim>::
print_fuck(number x){
      //double y = abc();
      double y = cfun();        //这里使用的函数是在头文件fun.h中声明的一个c语言函数
   } 

#endif

在Fuck类的静态成员函数中,用到了一个外部的函数cfun(),这个函数是在另外一个.h文件中声明并在另外一个.c文件中实现的,也就是说这个函数是一个c语言函数,而非c++函数。

fun.h和fun.c文件很简单:

//fun.h文件
#ifndef _MMS_H
#define _MMS_H

#ifdef __cplusplus     //这里是根据常见的C++调用C的方式
extern "C"{
#endif

  double cfun();       //声明了这么一个函数

#ifdef __cplusplus
}
#endif

#endif
//fun.c文件
#include "fun.h"

double cfun(){
   return -1;
}

上述文件直接编译链接是可行的,但单步调试会发现:运行到cfun()文件时,调用的其实是一个库文件(我也没看出来这个文件是怎么被引入的,位于哪儿),而非我们自己实现的那个cfun()文件。

假如我们把cfun函数名改成别的名称如abc(),那就会出现链接失败的提示。

这就是为什么起初的时候我会觉得很诡吊,因为同样一套程序,仅仅把函数名换了一下,结果就不能链接了!

但为什么以abc()函数实现的上面这个程序无法链接成功呢?

原因应该在于使用了make来编译

如果我用g++或gcc分别编译main.cc和fun.c文件为目标文件,再链接的话就成功。而且调试也是正常运行的。但如果用makefile文件来建立工程的话,最后就是链接失败。但具体原因仍然不明

猜你喜欢

转载自blog.csdn.net/qq_41230365/article/details/83272379