如何在C ++项目中使用C源文件?

在C ++项目中,由于C和C ++之间的标准不同,包括C源文件的.h文件会导致许多错误。
如何在C ++项目(或main.cpp)中使用C源文件?

为了最大可靠性:

  • 使用C编译器编译C源代码。
  • 使用C ++编译器编译C ++源代码
  • 最好在C ++中编写main()函数。
  • 将程序与C ++编译器链接。

确保C头本身知道C ++,或者C ++代码包含extern "C" { ... }块内的C头。

要么(C头文件cheader.h ):

 #ifndef CHEADER_H_INCLUDED #define CHEADER_H_INCLUDED #ifdef __cplusplus extern "C" { #endif ...main contents of header... #ifdef __cplusplus } #endif #endif /* CHEADER_H_INCLUDED */ 

或(C ++源代码):

 extern "C" { #include "cheader.h" } 

现代C风格非常接近C和C ++语言的通用子集。 但是,由于任何原因,任意C代码都不是C ++代码,只是调用C源文件C ++源文件(通过更改扩展,或者只是通过使用C ++编译器编译)并不能保证成功。 通常,将C编译为C和C ++作为C ++更容易,然后将生成的目标文件与C ++编译器链接(以确保调用正确的支持库)。

但是,如果MSVC编译器说使用MFC的程序必须只用C ++编写( MFC需要C ++编译(使用.cpp后缀)是报告的错误),那么你可能别无选择,只能确保你的C代码可编译为C ++代码。 这意味着您必须从malloc()等转换返回值; 你不得不担心其他你不使用强制转换将void *转换成其他指针类型的地方; 你必须担心C中的sizeof('a') == 4和C ++中的sizeof('a') == 1 ; 你必须确保在使用之前声明每个函数; 你必须确保你的C代码不使用任何C ++关键字(特别是typenameclass ;有时也inline – 但完整的列表非常大)。

在某些圈子中,您必须担心在C99中使用C ++ 2003或C ++ 2011中没有的function,例如灵活的数组成员,指定的初始化器,复合文字,可变长度数组等等。上。 但是,如果C代码用于MSVC,那么这可能不会成为问题; MSVC C编译器不支持这些function(它只支持C89,而不支持C99)。

FWIW:我有一个脚本来搜索C ++关键字。 它包含以下注释:

 # http://en.cppreference.com/w/cpp/keywords # plus JL annotations # and C () # and_eq C () # alignas (C++11 feature) # alignof (C++11 feature) # asm C (core) # auto(1) C (core) # bitand C () # bitor C () # bool C99 () # break C (core) # case C (core) # catch # char C (core) # char16_t (C++11 feature) # char32_t (C++11 feature) # class # compl C () # const C (core) # constexpr (C++11 feature) # const_cast # continue C (core) # decltype (C++11 feature) # default(1) C (core) # delete(1) # double C (core) # dynamic_cast # else C (core) # enum C (core) # explicit # export # extern C (core) # false C99 () # float C (core) # for C (core) # friend # goto C (core) # if C (core) # inline C (core) # int C (core) # long C (core) # mutable # namespace # new # noexcept (C++11 feature) # not C () # not_eq C () # nullptr (C++11 feature) # operator # or C () # or_eq C () # private # protected # public # register C (core) # reinterpret_cast # return C (core) # short C (core) # signed C (core) # sizeof C (core) # static C (core) # static_assert (C++11 feature) # static_cast # struct C (core) # switch C (core) # template # this # thread_local (C++11 feature) # throw # true C99 () # try # typedef C (core) # typeid # typename # union C (core) # unsigned C (core) # using(1) # virtual # void C (core) # volatile C (core) # wchar_t C (core) # while C (core) # xor C () # xor_eq C () 

(1)后缀是CPP参考文献的脚注:

  • (1) – 在C ++ 11中改变了意思

C ++向C源宣扬“向后兼容性”,因此可以选择将C源复制到.cpp文件并构建。 现在C ++ 并不是完全向后兼容的,所以你可能需要在C源代码中改变一些东西,但通常它应该以最小的错误构建。 只要确保包含.c使用的C库(考虑到你的编译器也支持C)

 #include  #include  //so on 

如果您只是使用源代码而不是一些预编译库,在大多数情况下,您可以将.c文件重命名为.cpp文件

来自C ++示例的最小可运行C

从C ++调用C非常简单:每个C函数只有一个可能的非破坏符号,因此不需要额外的工作。

main.cpp中:

 #include  #include "ch" int main() { assert(f() == 1); } 

CH:

 #ifndef C_H #define C_H /* This ifdef allows the header to be used from both C and C++. */ #ifdef __cplusplus extern "C" { #endif int f(); #ifdef __cplusplus } #endif #endif 

抄送:

 #include "ch" int f() { return 1; } 

跑:

 g++ -c -o main.o -std=c++98 main.cpp gcc -c -o co -std=c89 cc g++ -o main.out main.o co ./main.out 

我更详细地解释了extern "C" : 外部“C”在C ++中的作用是什么?

GitHub上的示例 。

来自C示例的最小可运行C ++

从中调用C ++有点困难:我们必须手动创建我们想要公开的每个函数的非破坏版本。

这里我们说明如何将C ++函数重载暴露给C.

main.c中:

 #include  #include "cpp.h" int main(void) { assert(f_int(1) == 2); assert(f_float(1.0) == 3); return 0; } 

cpp.h:

 #ifndef CPP_H #define CPP_H #ifdef __cplusplus // C cannot see these overloaded prototypes, or else it would get confused. int f(int i); int f(float i); extern "C" { #endif int f_int(int i); int f_float(float i); #ifdef __cplusplus } #endif #endif 

cpp.cpp:

 #include "cpp.h" int f(int i) { return i + 1; } int f(float i) { return i + 2; } int f_int(int i) { return f(i); } int f_float(float i) { return f(i); } 

跑:

 gcc -c -o main.o -std=c89 -Wextra main.c g++ -c -o cpp.o -std=c++98 cpp.cpp g++ -o main.out main.o cpp.o ./main.out 

GitHub上的示例 。