Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use C source files in a C++ project?

Tags:

c++

c

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

like image 255
Al2O3 Avatar asked Dec 04 '12 01:12

Al2O3


People also ask

Can you include source files in C?

You can properly include . C or . CPP files into other source files.

What is a source C file?

A C file is a source code file for a C or C++ program. It may include an entire program's source code, or may be one of many source files referenced within a programming project. C files can be edited using a basic text editor, but will not show syntax highlighting like most software development programs do.

Can you use C files in C++?

If the C++ compiler provides its own versions of the C headers, the versions of those headers used by the C compiler must be compatible. Oracle Developer Studio C and C++ compilers use compatible headers, and use the same C runtime library. They are fully compatible.

How do I add C files to Visual Studio?

In the Solution Explorer, right click 'Source Files', choose 'Add' and 'New item' to add a new item. Select 'Visual C++' and 'C++ File(. cpp)'. Change the file extension from .


2 Answers

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
like image 127
Jonathan Leffler Avatar answered Sep 28 '22 23:09

Jonathan Leffler


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.