Mixing C and C++

Overview

The C++ compiler may modify the names of symbols when compiling C++ code: Using a C++ compiler, the following code compiles just fine, however, it generates a linker error: (main.cpp)
int NonExistentFunction(int a, int b);

int main()
{
  int x = NonExistentFunction(1, 2);
  return 0;    
}
This is the error message from the linker from GNU g++:
/tmp/ccl1aw52.o: In function `main':                                                        
main.cpp:(.text+0x13): undefined reference to `NonExistentFunction(int, int)'               
collect2: error: ld returned 1 exit status
and Microsoft's linker says this:
error LNK2001: unresolved external symbol "int __cdecl NonExistentFunction(int,int)" (?NonExistentFunction@@YAHHH@Z)
Pretty obvious what the problem is, huh?

To undecorate the name, you can use a tool that comes with Visual Studio called undname:

undname ?NonExistentFunction@@YAHHH@Z
and this is the output:
Microsoft (R) C++ Name Undecorator
Copyright (C) Microsoft Corporation. All rights reserved.

Undecoration of :- "?NonExistentFunction@@YAHHH@Z"
is :- "int __cdecl NonExistentFunction(int,int)"
You can also use the dumpbin program from Microsoft to show all of the symbols in the object file:
dumpbin /symbols main.obj
Output:
Microsoft (R) COFF/PE Dumper Version 14.00.23026.0
Copyright (C) Microsoft Corporation.  All rights reserved.

Dump of file main.obj

File Type: COFF OBJECT

COFF SYMBOL TABLE
000 010559F2 ABS    notype       Static       | @comp.id
001 80000190 ABS    notype       Static       | @feat.00
002 00000000 SECT1  notype       Static       | .drectve
    Section length   2F, #relocs    0, #linenums    0, checksum        0
004 00000000 SECT2  notype       Static       | .debug$S
    Section length   90, #relocs    0, #linenums    0, checksum        0
006 00000000 SECT3  notype       Static       | .text$mn
    Section length   1E, #relocs    1, #linenums    0, checksum 63728334
008 00000000 UNDEF  notype ()    External     | ?NonExistentFunction@@YAHHH@Z (int __cdecl NonExistentFunction(int,int))
009 00000000 SECT3  notype ()    External     | main
00A 00000000 SECT3  notype       Label        | $LN3
00B 00000000 SECT4  notype       Static       | .xdata
    Section length    8, #relocs    0, #linenums    0, checksum 37887F31
00D 00000000 SECT4  notype       Static       | $unwind$main
00E 00000000 SECT5  notype       Static       | .pdata
    Section length    C, #relocs    3, #linenums    0, checksum 69312319
010 00000000 SECT5  notype       Static       | $pdata$main

String Table Size = 0x3B bytes

  Summary

          90 .debug$S
          2F .drectve
           C .pdata
          1E .text$mn
           8 .xdata
To see the symbols from g++, use objdump
objdump -t main.o
Output:
main.o:     file format elf64-x86-64

SYMBOL TABLE:
0000000000000000 l    df *ABS*  0000000000000000 main.cpp
0000000000000000 l    d  .text  0000000000000000 .text
0000000000000000 l    d  .data  0000000000000000 .data
0000000000000000 l    d  .bss   0000000000000000 .bss
0000000000000000 l    d  .note.GNU-stack        0000000000000000 .note.GNU-stack
0000000000000000 l    d  .eh_frame      0000000000000000 .eh_frame
0000000000000000 l    d  .comment       0000000000000000 .comment
0000000000000000 g     F .text  0000000000000021 main
0000000000000000         *UND*  0000000000000000 _Z19NonExistentFunctionii
You can also use the nm tool:
nm main.o
Output:
0000000000000000 T main
                 U _Z19NonExistentFunctionii
To undecorate the name, there is a tool called c++filt:
c++filt -t _Z19NonExistentFunctionii
Output:
NonExistentFunction(int, int)
You can do an entire object file by using c++filt as a filter
nm main.o | c++filt
Output:
0000000000000000 T main
                 U NonExistentFunction(int, int

The previous error was generated on purpose. Let's see how we might get it "not on purpose."

This is a C++ program that compiles and links just fine as expected: (main2.cpp)

#include <iostream>

void cpp_swap_p(int *a, int *b)
{
  int temp = *a;
  *a = *b;
  *b = temp;
}

int main()
{
  int x = 1, y = 2;
  cpp_swap_p(&x, &y);
  std::cout << "x = " << x << ", y = " << y << std::endl;

  return 0;    
}
Now, suppose we want to use the swap function in a C program. We've created a file (cpp_swap.cpp) that contains the function:
void cpp_swap_p(int *a, int *b)
{
  int temp = *a;
  *a = *b;
  *b = temp;
}
And we've got a C file: (main.c)
#include <stdio.h>

// prototype (could be in a .h file)
void cpp_swap_p(int *a, int *b);

int main(void)
{
  int a = 1, b = 2;
  cpp_swap_p(&a, &b);
  printf("a = %i, b = %i\n", a, b);

  return 0;    
}
Now we compile each file separately:
gcc -c main.c -o main.o
g++ -c cpp_swap.cpp -o cpp_swap.o
Then we link them together:
gcc main.o cpp_swap.o
And we get a linker error:
main.o: In function `main':
main.c:(.text+0x25): undefined reference to `cpp_swap_p'
collect2: error: ld returned 1 exit status
We also get the same error if we try to link with g++. Given the example name mangling above, it should be clear what the problem is. Running nm on the C++ object file (cpp_swap.o) shows the mangled name:
0000000000000000 T _Z10cpp_swap_pPiS_
We can verify the actual name with c++filt
c++filt _Z10cpp_swap_pPiS_
Output:
cpp_swap_p(int*, int*)
We need to modify the C++ code so that C code can access it. We simply use the extern keyword and specify the language as a string:
extern "C" void cpp_swap_p(int *a, int *b)
{
  int temp = *a;
  *a = *b;
  *b = temp;
}
To see that it works, run nm on the object file again:
0000000000000000 T cpp_swap_p
The cpp_swap_p function is now accessible from C and will link. Incidentally, you can put any language in the double quotes after the extern keyword as long as it's C. Actually, you can also put C++, but that's the default. This will mangle the name:
extern "C++" void cpp_swap_p(int *a, int *b)

Another thing that should be clear: Each C++ compiler has it's own way of mangling names. This means that you can't compile some files with one compiler and other files with a different compiler and expect them to work together. They will only work if the compilers each output compatible object code.

Overloading example

Given this code:
void fn();
void fn(int);
void fn(double);
void fn(int, double);
void fn(double, int);
int fn(int, int);

int main()
{
  fn();
  fn(1);
  fn(1.0);
  fn(1, 1.0);
  fn(1.0, 1);
  fn(1, 1);
  return 0;    
}
These are the errors that are emitted by the linker (Microsoft):

error LNK2001: unresolved external symbol "int __cdecl fn(int,int)" (?fn@@YAHHH@Z)	
error LNK2001: unresolved external symbol "void __cdecl fn(double,int)" (?fn@@YAXNH@Z)
error LNK2001: unresolved external symbol "void __cdecl fn(int,double)" (?fn@@YAXHN@Z)
error LNK2001: unresolved external symbol "void __cdecl fn(double)" (?fn@@YAXN@Z)
error LNK2001: unresolved external symbol "void __cdecl fn(int)" (?fn@@YAXH@Z)
error LNK2001: unresolved external symbol "void __cdecl fn(void)" (?fn@@YAXXZ)
Borland mangles the functions like this:

Function namesMangled names
void fn(void)
void fn(int)
void fn(double)
void fn(int, double)
void fn(double, int)
int fn(int, int)
@fn$qv
@fn$qi
@fn$qd
@fn$qid
@fn$qdi
@fn$qii        

GNU g++ mangles the functions like this (Clang is the same):

Function namesMangled names
void fn(void)
void fn(int)
void fn(double)
void fn(int, double)
void fn(double, int)
int fn(int, int)
__Z2fnv
__Z2fni
__Z2fnd
__Z2fnid
__Z2fndi
__Z2fnii


More uses of extern:

This code would presumably be compiled with a C++ compiler:

extern "C" void cpp_swap_p(int *a, int *b);
extern "C" void cpp_swap_r(int &a, int &b);

void cpp_swap_p(int *a, int *b)  // using pointers
{
  int temp = *a;
  *a = *b;
  *b = temp;
}

void cpp_swap_r(int &a, int &b)  // using references
{
  int temp = a;
  a = b;
  b = temp;
}
Or, we could tag a block of functions:
extern "C" 
{
  void cpp_swap_p(int *a, int *b); // using pointers
  void cpp_swap_r(int &a, int &b); // using references
}

Wrapping C header files in C++

Note the C code using pointers instead of references:

#include <stdio.h>

// prototypes (could be in a .h file)
void cpp_swap_p(int *a, int *b);  // using pointers
void cpp_swap_r(int *a, int *b);  // using pointers (no references in C)

int main()
{
  int a = 1, b = 2;

  cpp_swap_p(&a, &b);
  printf("a = %i, b = %i\n", a, b);
  
  cpp_swap_r(&a, &b);
  printf("a = %i, b = %i\n", a, b);
  return 0;    
}

Outupt:
a = 2, b = 1
a = 1, b = 2

Using the STL in C

Who knew?

Yes, you can do that. These examples are somewhat contrived, but you should be able to see the big picture. Suppose you want to sort an array of integers using std::sort from the STL. (For now, ignore the fact that the C standard library already has a sort function...)

Here's our C-compatible sort function written in C++ that uses the STL: (sort.cpp)

#include <algorithm> // sort

extern "C" void stl_sort(int *array, int size, bool (*compare)(int a, int b))
{
  std::sort(array, array + size, compare);
}
A C driver: (driver.c)
#include <stdio.h>
#include <stdlib.h>

/* Prototype for STL sort in C++ code */
void stl_sort(int *array, int size, int (*compare)(int a, int b));

/* For sorting with greater than */
int greater(int a, int b)
{
  return a > b;
}

/* For sorting with less than */
int less(int a, int b)
{
  return a < b;
}

/* Calculate sum of digits */
int sumhelper(int a)
{
  int sum = 0;
  while (a)
  {
    sum += a % 10;
    a /= 10;
  }
  return sum;
}

/* For sorting by sum of digits (greatest) */
int sumdigits(int a, int b)
{
  int suma = sumhelper(a);
  int sumb = sumhelper(b);
  return suma > sumb;
}

int RandomInt(int low, int high)
{
  int number = rand() % (high - low + 1) + low;
  return number;
}

void dump(int *array, int size)
{
  int i;
  for (i = 0; i < size; i++)
    printf("%i ", array[i]);
  printf("\n");
}

int main(void)
{
  int size = 50;
  int *array = malloc(size * sizeof(int));
  int i;

    /* Populate array with random integers */
  for (i = 0; i < size; i++)
    array[i] = RandomInt(1, 500);

    /* Print out unsorted array */
  printf("Unsorted:\n");
  dump(array, size);

    /* Sort the array smallest to largest */
  stl_sort(array, size, less);

    /* Print out sorted array */
  printf("Sorted small to large:\n");
  dump(array, size);

    /* Sort the array largest to smallest */
  stl_sort(array, size, greater);

    /* Print out sorted array */
  printf("Sorted large to small:\n");
  dump(array, size);

    /* Sort the array by sum of digits */
  stl_sort(array, size, sumdigits);

    /* Print out sorted array */
  printf("Sorted by sum of digits:\n");
  dump(array, size);

  free(array);
  return 0;
}
Compile the files and link them:
gcc -c driver.c -Wall -Wextra -ansi -pedantic -O2
g++ -c sort.cpp -Wall -Wextra -ansi -pedantic -O2
gcc driver.o sort.o -o sort
Output:
Unsorted:
384 387 278 416 294 336 387 493 150 422 363 28 191 60 264 427 41 427 173 237 212 369 68 430 283 
31 363 124 68 136 430 303 23 59 70 168 394 457 12 43 230 374 422 420 285 38 199 325 316 371 

Sorted small to large:
12 23 28 31 38 41 43 59 60 68 68 70 124 136 150 168 173 191 199 212 230 237 264 278 283 285 294 
303 316 325 336 363 363 369 371 374 384 387 387 394 416 420 422 422 427 427 430 430 457 493 

Sorted large to small:
493 457 430 430 427 427 422 422 420 416 394 387 387 384 374 371 369 363 363 336 325 316 303 294 
285 283 278 264 237 230 212 199 191 173 168 150 136 124 70 68 68 60 59 43 41 38 31 28 23 12 

Sorted by sum of digits:
199 369 387 387 278 493 394 457 168 285 384 294 68 68 59 374 283 427 427 363 336 363 237 264 173 
38 191 416 371 28 325 136 316 422 422 43 430 124 70 430 420 60 150 303 41 212 230 23 31 12 

Using an Object-Oriented SpellChecker in C

Here's a more real-world example of calling a method on an C++ object.

FileStrings.h (Text) This file is the C++ interface that is used by the C++ code.

SpellChecker.h (Text) This is the C interface to the C++ code that will be called by C code.

SpellChecker.cpp (Text) This is the C++ implementation of the C interface.

spellcheck.c (Text) This is the C code that will call the C++ code via the C interface.

Compiling the C and C++ files, then linking: (You have to provide FileStrings.cpp)

gcc -c spellcheck.c -Wall -Wextra -ansi -pedantic -O2 -g
g++ -c FileStrings.cpp -Wall -Wextra -ansi -pedantic -O2 -g
g++ -c SpellChecker.cpp -Wall -Wextra -ansi -pedantic -O2 -g
g++ spellcheck.o SpellChecker.o FileStrings.o -o spell
The output from running the executable should look like this:
Four is correct.
SCORE is correct.
and is correct.
sevn is incorrect.
years is correct.
ago is correct.
ar is correct.
fawthers is incorrect.
brought is correct.
foarth is incorrect.
on is correct.
this is correct.
contnent is incorrect.
a is correct.
gnu is correct.
nashun is incorrect.
If you don't have FileStrings.cpp, you can just use one of these object files that was compiled for the appropriate platform. You'll want to rename it to simply FileStrings.o to use with the command lines above.

FileStrings.o-linux64 - Compiled with 64-bit g++ (v. 5.3.0) on Linux.
FileStrings.o-cygwin64 - Compiled with 64-bit Cygwin g++ (v. 5.4.0) on Windows.
FileStrings.o-vc64 - Compiled with Microsoft's 64-bit compiler (v. 19.0, VS 14.0) on Windows.
FileStrings.o-macos64 - Compiled with 64-bit clang++ (Apple LLVM v. 8.0.0) on MacOS.

Example to Try on Your Own

The goal is to "fix" this existing code so that it compiles (without warnings) and produces this output:

In C: i = 5, d = 5
In CPP: i = 5, d = 5
The output indicates that after the C code prints its information, it calls the cpp_stuff function to do its work.

This is the start of CFile.c:

int main()
{
  int i = sqrt(25.0);
  double d = sqrt(25.0);
  printf("In C: i = %i, d = %g\n", i, d);
  return 0;
}
This is the start of CPPFile.cpp:
void cpp_stuff()
{
  int i = sqrt(25.0);
  double d = sqrt(25.0);
  printf("In CPP: i = %i, d = %g\n", i, d);
}
Commands to compile and link:
gcc -c CFile.c -Wall -Wextra -ansi -pedantic -O2
g++ -c CPPFile.cpp -Wall -Wextra -ansi -pedantic -O2
gcc CFile.o CPPFile.o -o mix
Solutions