混合C/C++项目调用GMP库编译失败的根因排查请求
混合C/C++项目调用GMP库编译失败的根因排查请求
问题背景
我有一个包含C和C文件的项目,C文件使用了GMP库,C文件包含main函数并调用C文件中的函数。以下是我的代码:
point.h
#ifndef POINT_H #define POINT_H #ifdef __cplusplus extern "C" { #endif #include <gmp.h> typedef struct { mpz_t x; mpz_t y; } Point; void init_point(Point* p); void clear_point(Point* p); void print_point(const Point* p); #ifdef __cplusplus } #endif #endif // POINT_H
point.c
#include <stdio.h> #include "point.h" void init_point(Point* p) { mpz_init(p->x); mpz_init(p->y); mpz_set_ui(p->x, 42); mpz_set_ui(p->y, 17); } void clear_point(Point* p) { mpz_clear(p->x); mpz_clear(p->y); } void print_point(const Point* p) { gmp_printf("Point(x = %Zd, y = %Zd)\n", p->x, p->y); }
main.cpp
extern "C" { #include "point.h" } int main() { Point p; init_point(&p); print_point(&p); clear_point(&p); return 0; }
编译错误信息
C文件的目标文件能成功编译,但C++文件编译失败,错误输出如下:
[ 33%] Building C object CMakeFiles/gmp_example.dir/point.c.o [ 66%] Building CXX object CMakeFiles/gmp_example.dir/main.cpp.o In file included from /usr/include/c++/13/bits/stringfwd.h:40, from /usr/include/c++/13/iosfwd:41, from /usr/include/x86_64-linux-gnu/gmp.h:35, from /mnt/HDD_Small/Bitcoin_Jumper/src/gmp/point.h:8, from /mnt/HDD_Small/Bitcoin_Jumper/src/gmp/main.cpp:2: /usr/include/c++/13/bits/memoryfwd.h:64:3: error: template with C linkage 64 | template<typename> | ^~~~~~~~ /mnt/HDD_Small/Bitcoin_Jumper/src/gmp/point.h:5:1: note: ‘extern "C"’ linkage started here 5 | extern "C" { | ^~~~~~~~~~ /usr/include/c++/13/bits/memoryfwd.h:67:3: error: template specialization with C linkage 67 | template<> | ^~~~~~~~ /mnt/HDD_Small/Bitcoin_Jumper/src/gmp/point.h:5:1: note: ‘extern "C"’ linkage started here 5 | extern "C" { | ^~~~~~~~~~ /usr/include/c++/13/bits/memoryfwd.h:73:3: error: template with C linkage 73 | template<typename, typename> | ^~~~~~~~ /mnt/HDD_Small/Bitcoin_Jumper/src/gmp/point.h:5:1: note: ‘extern "C"’ linkage started here 5 | extern "C" { | ^~~~~~~~~~ ... /usr/include/c++/13/iosfwd:217:3: error: template with C linkage 217 | template<typename _CharT, typename _Traits = char_traits<_CharT>, | ^~~~~~~~ /mnt/HDD_Small/Bitcoin_Jumper/src/gmp/point.h:5:1: note: ‘extern "C"’ linkage started here 5 | extern "C" { | ^~~~~~~~~~ /usr/include/x86_64-linux-gnu/gmp.h:2293:33: error: conflicting declaration of C function ‘std::ostream& operator<<(std::ostream&, mpq_srcptr)’ 2293 | __GMP_DECLSPEC_XX std::ostream& operator<< (std::ostream &, mpq_srcptr); | ^~~~~~~~ /usr/include/x86_64-linux-gnu/gmp.h:2292:33: note: previous declaration ‘std::ostream& operator<<(std::ostream&, mpz_srcptr)’ 2292 | __GMP_DECLSPEC_XX std::ostream& operator<< (std::ostream &, mpz_srcptr); | ^~~~~~~~ /usr/include/x86_64-linux-gnu/gmp.h:2294:33: error: conflicting declaration of C function ‘std::ostream& operator<<(std::ostream&, mpf_srcptr)’ 2294 | __GMP_DECLSPEC_XX std::ostream& operator<< (std::ostream &, mpf_srcptr); | ^~~~~~~~ /usr/include/x86_64-linux-gnu/gmp.h:2292:33: note: previous declaration ‘std::ostream& operator<<(std::ostream&, mpz_srcptr)’ 2292 | __GMP_DECLSPEC_XX std::ostream& operator<< (std::ostream &, mpz_srcptr); | ^~~~~~~~ /usr/include/x86_64-linux-gnu/gmp.h:2296:33: error: conflicting declaration of C function ‘std::istream& operator>>(std::istream&, mpq_ptr)’ 2296 | __GMP_DECLSPEC_XX std::istream& operator>> (std::istream &, mpq_ptr); | ^~~~~~~~ /usr/include/x86_64-linux-gnu/gmp.h:2295:33: note: previous declaration ‘std::istream& operator>>(std::istream&, mpz_ptr)’ 2295 | __GMP_DECLSPEC_XX std::istream& operator>> (std::istream &, mpz_ptr); | ^~~~~~~~ /usr/include/x86_64-linux-gnu/gmp.h:2297:33: error: conflicting declaration of C function ‘std::istream& operator>>(std::istream&, mpf_ptr)’ 2297 | __GMP_DECLSPEC_XX std::istream& operator>> (std::istream &, mpf_ptr); | ^~~~~~~~ /usr/include/x86_64-linux-gnu/gmp.h:2295:33: note: previous declaration ‘std::istream& operator>>(std::istream&, mpz_ptr)’ 2295 | __GMP_DECLSPEC_XX std::istream& operator>> (std::istream &, mpz_ptr); | ^~~~~~~~ make[2]: *** [CMakeFiles/gmp_example.dir/build.make:93: CMakeFiles/gmp_example.dir/main.cpp.o] Error 1 make[1]: *** [CMakeFiles/Makefile2:87: CMakeFiles/gmp_example.dir/all] Error 2 make: *** [Makefile:91: all] Error 2
我尝试过移动C文件中extern "C"的位置,也试过移除它,但都没有解决问题,已经花了半天时间还是没搞定(不过没有GMP的测试项目是能成功编译的)。
根因分析与解决方案
问题到底出在哪?
咱们直接点:你在main.cpp里把整个point.h都硬塞进extern "C"块里了,这才是罪魁祸首!
你看,point.h本身已经包含了<gmp.h>,而GMP的头文件可不是纯C代码——它里面专门为C做了适配,比如有std::ostream的重载运算符,还有一些依赖C模板的内容。但extern "C"是C语言的链接规范,这个作用域里根本不允许出现C特有的东西(比如模板、函数重载),所以当编译器在extern "C"里读到GMP的C代码时,直接就报错了。
而且你根本没必要手动包extern "C",因为你的point.h本身就写了完美的C/C兼容逻辑:通过#ifdef __cplusplus判断,当C编译器包含它时,会自动把函数声明用extern "C"包裹,完全不用你在main.cpp里多此一举。
修复方案(超简单)
把main.cpp里的extern "C"块删掉,直接包含point.h就行:
#include "point.h" int main() { Point p; init_point(&p); print_point(&p); clear_point(&p); return 0; }
额外提醒
另外别忘了在你的构建脚本(比如CMakeLists.txt)里正确链接GMP库,不然最后链接阶段还是会报错。比如CMake里要加这些内容:
# 找到GMP库 find_package(GMP REQUIRED) # 把GMP库链接到你的目标 target_link_libraries(gmp_example PRIVATE GMP::GMP)
这样改完重新编译,肯定就能跑通了!
内容来源于stack exchange
相关产品推荐
相关产品推荐

