31

In a C++ project, including .h files of C source files will cause many errors because of different standards between C and C++.
How to use C source files in a C++ project (or in main.cpp)?

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Al2O3
  • 3,103
  • 4
  • 26
  • 52
  • 6
    Compile the C source with a C compiler; compile the C++ source with a C++ compiler; (preferably, write the `main()` function in C++); link the program with a C++ compiler. – Jonathan Leffler Dec 04 '12 at 01:15
  • 1
    can you elabourate on what you tried and what were the errors? – Karthik T Dec 04 '12 at 01:15
  • 2
    Incompatibilities are few and far between. You're going to have to "fix" the C files to be C++ compatible if you want to use them in a C++ compiler or you can link the C object files separately. The only problem I've encountered personally is C's implicit conversion from `void*` to any other pointer type. – Ed S. Dec 04 '12 at 01:15
  • Actually, it shouldn't give you problems since C++ recognizes standard C. The best practice is to correct the name of your libraries following the pattern: becomes . But it shouldn't be a problem – gibertoni Dec 04 '12 at 01:16
  • Use them in the same way as cpp files; don't forget to `include` headers with `extern "C"`. – Sergey Kalinichenko Dec 04 '12 at 01:16
  • 1
    @KuramaYoko There are many perfectly legal (even idomatic) constructs in c that will throw a error in a c++ compiler. Even `int *i = malloc(sizeof(int) * 10);` is illegal in c++. So is any code that uses `class` as a variable name or uses c99 dynamic arrays or or or... – dmckee --- ex-moderator kitten Dec 04 '12 at 01:18
  • What about " MFC requires C++ compilation (use a .cpp suffix) " error? @KarthikT – Al2O3 Dec 04 '12 at 01:24
  • @dmckee You are right. But I thought he meant problems with the standard libraries not with his c code. – gibertoni Dec 04 '12 at 01:26
  • This particular error sounds like it just needs you to rename c -> cpp to fix this one. Alternatively check this project’s option: C/C++ -> Advanced -> Compile As. It should be set to “Compile as C++ Code (/TP)” - from http://social.msdn.microsoft.com/Forums/eu/vclanguage/thread/aa6e597b-dfb6-42e2-a46b-3756df0f411f – Karthik T Dec 04 '12 at 01:27
  • In cpp file, if I include .h of c files which contains function declarations , it causess errors: error LNK2019: unresolved extern symbol...(function name)? – Al2O3 Dec 04 '12 at 02:06

4 Answers4

44

For the maximum reliability:

  • Compile the C source with a C compiler.
  • Compile the C++ source with a C++ compiler
  • Preferably, write the main() function in C++.
  • Link the program with a C++ compiler.

Make sure that the C headers are either themselves aware of C++ or that the C++ code includes the C headers inside an extern "C" { ... } block.

Either (C header file 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 */ 

or (C++ source code):

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

Modern C style is very close to the common subset of the C and C++ languages. However, arbitrary C code is not C++ code for any of a very large number of reasons, and simply calling the C source files C++ source files (by changing the extension, or simply by compiling with the C++ compiler) is not guaranteed to be successful. In general, it is easier to compile C as C and C++ as C++ and then link the resulting object files with the C++ compiler (to ensure the correct support libraries are invoked).

However, if the MSVC compiler is saying that programs using MFC have to be written solely in C++ (MFC requires C++ compilation (use a .cpp suffix) is the reported error), then you may have no choice but to ensure that your C code is compilable as C++ code. That means you'll have to cast the return values from malloc() et al; you have to worry about other places where you do not use a cast to convert a void * into some other pointer type; you have to worry about sizeof('a') == 4 in C and sizeof('a') == 1 in C++; you have to ensure that every function is declared before it is used; you have to ensure your C code does not use any C++ keywords (typename, class in particular; also inline sometimes — but the complete list is quite large).

In some circles, you'd have to worry about the use of features in C99 that are not in C++2003 or C++2011, such as flexible array members, designated initializers, compound literals, variable-length arrays, and so on. However, if the C code is for MSVC, then that probably isn't going to be a problem; those features are not supported by the MSVC C compiler (it only supports C89, not C99).

FWIW: I have a script to hunt down C++ keywords. It contains the following comment:

# 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>)

The (1) suffixes is a footnote at CPP Reference:

  • (1) — meaning changed in C++11
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • " MFC requires C++ compilation (use a .cpp suffix) " – Al2O3 Dec 04 '12 at 01:25
  • Then you can't use C after all because MS doesn't allow it. Tough. You'll have to make sure your C code is also C++ code. That's harder work than making your C code into C code. Have fun — or choose a different O/S. (I don't know whether that error message means you can't use the `extern "C"` notation or not; I've not coded with MSVC and MFC.) Note that if you had mentioned the platform in your question, you might have gotten better answers straight away — and I might not have tried answering at all. – Jonathan Leffler Dec 04 '12 at 01:26
  • Followup question, if you don't mind @JonathanLeffler: [Using cmake to build a C++ project, how can one also specify in CMakeLists.txt to build a couple simple C files (in a third-party subdirectory if the C++ project)?](https://stackoverflow.com/questions/50054016/cmakelists-txt-for-third-party-c-files-within-c-project) – BoltzmannBrain Apr 27 '18 at 14:55
11

Minimal runnable C from C++ example

Calling C from C++ is pretty easy: each C function only has one possible non-mangled symbol, so no extra work is required.

main.cpp

#include <cassert>

#include "c.h"

int main() {
    assert(f() == 1);
}

c.h

#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

c.c

#include "c.h"

int f() { return 1; }

Run:

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

I have explained extern "C" in more detail at: What is the effect of extern "C" in C++?

Example on GitHub.

Minimal runnable C++ from C example

Calling C++ from is a bit harder: we have to manually create non-mangled versions of each function we want to expose.

Here we illustrate how to expose C++ function overloads to C.

main.c

#include <assert.h>

#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);
}

Run:

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

Example on GitHub.

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
2

C++ preaches "backwards compatibility" to C source, so an option would be to copy the C source onto a .cpp file and build. Now C++ is not COMPLETELY backwards compatible, so you might need to change some things around in the C source, but generally it should build with minimal errors. Just make sure you include the C library's that the .c uses(considering your compiler supports C also)

#include <stdio.h>
#include <string.h>
//so on
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Syntactic Fructose
  • 18,936
  • 23
  • 91
  • 177
0

if you are just using the source code and not some precompiled libraries, in most of the cases you could just rename the .c file to a .cpp file

Salchi13
  • 59
  • 3
  • But some global variables defined in .h of c files will cause many errors, and more other errors. – Al2O3 Dec 04 '12 at 01:20
  • that is why I said in most of the cases, but you are right... global variables are not a good practice anyway hehehe – Salchi13 Dec 04 '12 at 01:28
  • Renaming .c files works only if the C code is crap: It requires that the C is actually within the common subset of C and C++, which is not the case for good C code. For instance, there is a very good reason for C programmers to *not* cast the result of `malloc()`, C++ forces the cast. C has true multidimensional dynamic arrays, C++ has not. There are some more things that good C code does which is not allowed in C++, these are just two examples out of the top of my head. – cmaster - reinstate monica Aug 18 '18 at 22:16