Compiling CFile.c

The C file gives two compiler warnings something like:
CFile.c: In function 'main':
CFile.c:3:11: warning: implicit declaration of function 'sqrt' [-Wimplicit-function-declaration]
   int i = sqrt(25.0);
           ^
CFile.c:3:11: warning: incompatible implicit declaration of built-in function 'sqrt'
CFile.c:3:11: note: include '' or provide a declaration of 'sqrt'
CFile.c:5:3: warning: implicit declaration of function 'printf' [-Wimplicit-function-declaration]
   printf("In C: i = %i, d = %g\n", i, d);
   ^
CFile.c:5:3: warning: incompatible implicit declaration of built-in function 'printf'
CFile.c:5:3: note: include '' or provide a declaration of 'printf'
These warnings indicate that the compiler doesn't know what kinds of functions sqrt and printf are, so it assumes that they return an int, which is usually a poor assumption. To clue the compiler in as to their types, we need to specify the proper prototypes. This is easily done by including the header files where these functions are prototyped:
#include <math.h>
#include <stdio.h>
This suppresses the warnings about the functions being unknown. However, we still may get a warning for trying to assign a double to an integer. This is because the sqrt function returns a double, yet we are assigning it to an int. To suppress this warning, we need to cast the return value to an int:
int i = (int)sqrt(25.0);
Now the file will compile without warnings or errors. Note that not all compilers will warn about the possible loss of data.


Compiling CPPFile.cpp:

CPPFile.cpp: In function 'void cpp_stuff()':
CPPFile.cpp:3:20: error: 'sqrt' was not declared in this scope
   int i = sqrt(25.0);
                    ^
CPPFile.cpp:5:42: error: 'printf' was not declared in this scope
   printf("In CPP: i = %i, d = %g\n", i, d);
                                          ^
The C++ file has the same problems as the C file. However, if a function is called that the compiler hasn't seen yet, the compiler generates an error instead of a warning. We need to add the two includes as well as a cast. We can use a C++ cast in this case because we the code is C++:
#include <math.h>
#include <stdio.h>

int i = static_cast<int>(sqrt(25));
Or, if you would rather use the "C" versions of the header files (without the extension), you can do this:
#include <cmath>
#include <cstdio>
and then use std:: with each function. The C++ code now compiles without warnings or errors.

Wrapping C header files in C++


Linking the files and calling the C++ function from C

The program links without warnings or errors and generates this output:
In C: i = 5, d = 5
So we are almost there. To get the output from the C++ code, we need to call the C++ function from the C code by adding a call to it in main:
void main(void)
{
  int i = (int) sqrt(25);
  double d = sqrt(25);
  printf("In C: i = %i, d = %g\n", i, d);
  cpp_stuff();
}
This code generates a warning during the compile and an error during the link.
CFile.c: In function 'main':
CFile.c:9:3: warning: implicit declaration of function 'cpp_stuff' [-Wimplicit-function-declaration]
   cpp_stuff();
   ^
/tmp/cc6hK5Dl.o: In function `main':
CFile.c:(.text+0x43): undefined reference to `cpp_stuff'
collect2: error: ld returned 1 exit status
The reason the compiler generates a warning is because it doesn't know what cpp_stuff is. (The same problem we had with sqrt and printf). So, we need to prototype it in our C file. (We don't have a header file that we can include.) The linker error is because the C++ compiler mangled the function name into a non-C compatible function name.

To fix the compiler warning, we prototype the function before main:

void cpp_stuff(void);
To fix the linker error, we need to tell the C++ compiler to disable name mangling during the compile by using the extern keyword and then recompile the C++ file:
extern "C" void cpp_stuff(void)
{
  ...
}
Now we can build the C file and link with the C++ object file:
gcc CFile-original.c CPPFile-original.o -o mix
This fixes all of the problems we encountered when we attempted mix C and C++ code in the same project. The output from the program looks like:
In C: i = 5, d = 5
In CPP: i = 5, d = 5


The complete code for both files:

CFile.c:


#include <math.h>   /* for sqrt()   */
#include <stdio.h>  /* for printf() */

void cpp_stuff(void);

void main(void)
{
  int i = (int) sqrt(25);
  double d = sqrt(25);
  printf("In C: i = %i, d = %g\n", i, d);
  cpp_stuff();
}
CPPFile.cpp:

#include <math.h>   // for sqrt()
#include <stdio.h>  // for printf()

// use extern "C" so the C file can link to this
extern "C" void cpp_stuff(void)
{
  int i = (int)sqrt(25);
  double d = sqrt(25);
  printf("In CPP: i = %i, d = %g\n", i, d);
}