error: conflicts with new declaration with 'C' linkage 的根因深入深入深入剖析

这种错误伴随着还有一种未定义的错误,但是在c文件中函数确实定义了;

        最近在维护公司一个框架的时候发现,新添加的cpp代码编译后有的会报这样的错误,因此花了一点时间深入分析了一下这个问题的根本原因:

          这两个问题的根本原因是由于cpp文件和c文件分别被gcc(使用gcc编译c和cpp文件效果是一样的,只是最终链接成可执行文件必须要使用g++,因为gcc没有构造函数的初始化段)编译生成.o目标文件的时候对函数名这种强符号的处理方法不一样;

只想快速通过编译的看这里:

解决的方法就是通过extern "C"{函数声明或者头文件}  

场景:我需要在自己的cpp文件中引用c文件的函数,c文件不能更改只能更改我自己的cpp文件,

这个问题是你在当前文件中吧需要引用的C函数已经放在了extern ”C“里面,但是还包含了含有他的声明的头文件,当该cpp文件被预处理之后,其中就会有两个该函数的声明,并且两个声明一个加了extern ”C" 一个没有加所以会冲突,只要删除包含该函数的头文件#include<>就可以解决;或者把该头文件包含也放到extern "C"中,相当于声明了两次,但两次一致,也没有问题;


以下详细分析这两个错误的原因,

先说一个比较重要的东西,就是c++文件,和c文件他们在分别被编译成.o文件之后,他们本身对函数名的处理是不一样的,简单的例子如下:

add.c 文件,同样的文件内容只是后缀名不一样:

c文件编译结果,输出符号

cpp文件编译结果,输出符号

可以看到同样的函数内容只是文件后缀不一样使用gcc编译之后其对add这个函数名处理的方式不同,c++对外导出的符号是_Z3addii,而c语言就是add,这个区别原因在于c++语言的函数重载特性,因此c++语言在导出函数符号的时候会跟上函数参数标志,_Z3addii中其中ii就表示函数带两个int 形参数;而前缀则是调用惯例的不同对函数修饰规则不同;

说到这里,这个问题的原因也就很清楚了:

这就是由于cpp文件编译生成.o文件之后,其需要在其他的.o文件中寻找_Z3addii的函数,但是使用c语言编译的add.c文件中只有add符号,所以编译器会报未定义的错误;

想必大家也能理解extern "C"的作用了,extern会告诉编译器被他声明的函数使用c编译规则编译,这样在cpp文件中使用extern "C"声明函数之后,cpp生成的.o文件中就是add符号而不是_Z3addii符号,这样在链接的时候编译器就不会再报未定义的错误。

我们可以看一下结果:main.cpp 引用了add

未加extern”C“情况下:

在main.cpp中加上extern "C" 并删除头文件包含

结果如下

可以看到在加了extern"C"声明之后,函数add被按照c语言的函数编译;

总结:

第一个链接冲突的问题是由于在一个文件中包含了两个add函数的声明,这两个声明一个加了extern”C”一个没有加导致冲突,解决的办法就是删除头文件包含,只留下本文件中extern “C” 中的声明;

第二个问题是由于c++与c语言的编译对函数名的处理不同导致的,因此要使用extern"C"告诉编译器在cpp文件中引用的c函数需要使用c的编译规则来编译;

原创文章 7 获赞 3 访问量 952

猜你喜欢

转载自blog.csdn.net/w346665682/article/details/103094088
今日推荐