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

Al2*_*2O3 17 c c++

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

Jon*_*ler 29

为了最大可靠性:

  • 使用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 */ 
Run Code Online (Sandbox Code Playgroud)

或(C++源代码):

extern "C" {
#include "cheader.h"
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

# http://en.cppreference.com/w/cpp/keywords
# plus JL annotations
# and                               C (<iso646.h>)
# and_eq                            C (<iso646.h>)
# alignas (C++11 feature)
# alignof (C++11 feature)
# asm                               C (core)
# auto(1)                           C (core)
# bitand                            C (<iso646.h>)
# bitor                             C (<iso646.h>)
# bool                              C99 (<stdbool.h>)
# break                             C (core)
# case                              C (core)
# catch
# char                              C (core)
# char16_t (C++11 feature)
# char32_t (C++11 feature)
# class
# compl                             C (<iso646.h>)
# 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 (<stdbool.h>)
# 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 (<iso646.h>)
# not_eq                            C (<iso646.h>)
# nullptr (C++11 feature)
# operator
# or                                C (<iso646.h>)
# or_eq                             C (<iso646.h>)
# 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 (<stdbool.h>)
# 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 (<iso646.h>)
# xor_eq                            C (<iso646.h>)
Run Code Online (Sandbox Code Playgroud)

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

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


Cir*_*四事件 9

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

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

主程序

#include <cassert>

#include "c.h"

int main() {
    assert(f() == 1);
}
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

抄送

#include "c.h"

int f() { return 1; }
Run Code Online (Sandbox Code Playgroud)

跑:

g++ -c -o main.o -std=c++98 main.cpp
gcc -c -o c.o -std=c89 c.c
g++ -o main.out main.o c.o
./main.out
Run Code Online (Sandbox Code Playgroud)

我已经extern "C"更详细地解释了:在 C++ 中 extern "C" 的作用是什么?

GitHub 上的示例

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

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

这里我们说明如何向 C 公开 C++ 函数重载。

主文件

#include <assert.h>

#include "cpp.h"

int main(void) {
    assert(f_int(1) == 2);
    assert(f_float(1.0) == 3);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

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);
}
Run Code Online (Sandbox Code Playgroud)

跑:

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
Run Code Online (Sandbox Code Playgroud)

GitHub 上的示例