Mixing C++ with C/Objective-C

When working on a software project, you may sometimes have to mix programming languages.
It may be because you need to use some specific libraries, because of code portability needs, whatever.

When coding a Mac OS X (or iOS) application, you are usually going to use Objective-C as main language.
It's not mandatory, as you can use the old Carbon API, or stuff like QT (C++), but it will usually be easier, at least for all the UI related stuff.

Mixing C with Objective-C is not a problem, as Objective-C is a strict superset of C.
Whether you have pure C code, or if you are linking with a C library, there's no issue.

Mixing C or Objective-C with C++ is not as easy.
Although C++ was originally based on the C language, it's not strictly a superset, so trying to use C++ code from C or Objective-C may not be always easy.

Of course, with Objective-C, you have the possibility to use Objective-C++ (.mm files).
This way, you can use all the C++ features within Objective-C code.

But sometimes, this is not wanted. Moreover, it's of course impossible with pure C.

Before going on, let's take a little example in pure C.
We are going to code a typical «hello world» application.

For this, we decide to have a file for our program's main function, and another file for utility functions.

Let's start by the utility functions file.
First of all, we need to create a header file, named «lib.h»:

#ifndef __LIB_H__
#define __LIB_H__

void say_hello( void );

#endif

We declare here the prototype of a function named «say_hello».
We are now going to provide an implementation, in a new file named «lib.c»:

#include <stdio.h>
#include "lib.h"

void say_hello( void )
{
    printf( "hello, world\n" );
}

Nothing special here. Now let's create our program's main function, in a file named «main.c»:

#include "lib.h"

int main( void )
{
    say_hello();
    
    return 0;
}

Here, we just use our «say_hello» function, before exiting the program.

Let's take a look at the compilation. We are going to generate an object file (.o) for each C file, and then link them together.

Let's start with «lib.c»:

gcc -Wall -o lib.o -c lib.c

From the «lib.c» source file, we generate an object file (machine code) named «lib.o». We can use the «nm» command to list the symbols available in that object file:

nm lib.o

It will output:

0000000000000028 s EH_frame0
0000000000000015 s L_.str
                 U _puts
0000000000000000 T _say_hello
0000000000000040 S _say_hello.eh

We can see here our «say_hello» function.
As you can see, it has a leading underscore. This is totally normal.

Now let's create an object file from «main.c»:

gcc -Wall -o main.o -c main.c

Now, we have two distinct object files.
In order to create an executable, we need to link them. This can be done with:

gcc -Wall -o test lib.o main.o

This will create an executable named «test», which will just print «hello, world» when run.

Piece of cake.
But now imagine we want to use C++ for the library part, and C for the other parts.

First of all, we are going to rename «lib.c» to «lib.cpp».
The «lib.h» header doesn't need to be changed.

We are also going to replace the implementation of the «say_hello» function, so it uses «IOStream» instead of «printf()».
Our «lib.cpp» file will now look like that:

#include <iostream>
#include "lib.h"

void say_hello( void )
{
    std::cout << "hello, world" << std::endl;
}

No problem here, just a standard C++ hello world.
Let's recompile everything (note that we are now going to use g++ instead of gcc for the C++ file):

g++ -Wall -o lib.o -c lib.cpp
gcc -Wall -o main.o -c main.c

No problem here. Let's link the two files in order to create an executable, as previously:

gcc -Wall -o test lib.o main.o

Unfortunately, you'll have linker errors here, such as:

Undefined symbols for architecture x86_64:
  "std::cout", referenced from:
      say_hello()    in lib.o
  "std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)", referenced from:
      say_hello()    in lib.o
  "std::basic_ostream<char, std::char_traits<char> >& std::endl<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&)", referenced from:
      say_hello()    in lib.o
  "std::basic_ostream<char, std::char_traits<char> >::operator<<(std::basic_ostream<char, std::char_traits<char> >& (*)(std::basic_ostream<char, std::char_traits<char> >&))", referenced from:
      say_hello()    in lib.o
  "std::ios_base::Init::Init()", referenced from:
      __static_initialization_and_destruction_0(int, int)in lib.o
  "std::ios_base::Init::~Init()", referenced from:
      ___tcf_0 in lib.o
  "_say_hello", referenced from:
      _main in main.o
ld: symbol(s) not found for architecture x86_64
collect2: ld returned 1 exit status

Ok, obviously we are not linked with the C++ standard library.
This is because we used gcc to create our final executable.

So let's use g++ for the final stage.
Note that we will still use gcc for the «main.c» file, as it's still pure C code.
No need for a C++ compiler here:

g++ -Wall -o lib.o -c lib.cpp
gcc -Wall -o main.o -c main.c
g++ -Wall -o test lib.o main.o

We still got a linker error:

Undefined symbols for architecture x86_64:
  "_say_hello", referenced from:
      _main in main.o
ld: symbol(s) not found for architecture x86_64
collect2: ld returned 1 exit status

Here, we can see we are effectively linked with the C++ standard library, as the errors for the «std::» members, like «std::cout» are gone.

But it seems that the C++ version of our «say_hello» function is not found. Let's take a look at the «lib.o» file, to find out what's wrong. We are going to use the «nm» command again, to list the symbols available in that file:

nm lib.o

The result is:

0000000000000100 s EH_frame0
00000000000000eb s L_.str
0000000000000070 s __GLOBAL__I__Z9say_hellov
0000000000000148 s __GLOBAL__I__Z9say_hellov.eh
0000000000000090 s __Z41__static_initialization_and_destruction_0ii
0000000000000178 s __Z41__static_initialization_and_destruction_0ii.eh
0000000000000000 T __Z9say_hellov
0000000000000118 S __Z9say_hellov.eh
                 U __ZNSolsEPFRSoS_E
                 U __ZNSt8ios_base4InitC1Ev
                 U __ZNSt8ios_base4InitD1Ev
                 U __ZSt4cout
                 U __ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
00000000000001d8 b __ZStL8__ioinit
                 U __ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
                 U ___cxa_atexit
                 U ___dso_handle
0000000000000040 t ___tcf_0
00000000000001a8 s ___tcf_0.eh

There's no symbol for our «say_hello» function.
Instead, we have:

__Z9say_hellov

What's this «_Z9» prefix?
Ever heard of «name mangling»?

First of all, remember that C++ has built-in support for function overloading.
It means that the following example is perfectly valid:

void foo( int x );
void foo( double x );
int  foo( int x );

Here, we've got three functions named «foo».
In C or Objective-C, this is not possible, as a symbol can only be defined once.

In C++, this is called «function overloading». A function (or method) can have multiple implementations, as long as there is a difference in the return type and/or the arguments.

The compiler will then generate three different functions, and automatically choose which one to use when you issue a call, depending on the return type and the argument types.

In order to do this, as the compiler will create different functions, it will have to use different symbol names.
That's why C++ functions (or methods) have a modified symbol name, in the resulting object code.

So how can we deal with this, from our «main.c» file?
With Objective-C++, it would have worked, of course. But not with pure C, or pure Objective-C.

Fortunately, there is a way to tell the C++ compiler to comply with C-like declarations, so it won't use its calling conventions (with mangled names) when producing object code.

This way, our C++ function will be callable from pure-C (even if it's implementation uses C++ features).

In order to do this, we just need to change the «lib.h» header file:

#ifndef __LIB_H__
#define __LIB_H__

#ifdef __cplusplus
extern "C" {
#endif

void say_hello( void );

#ifdef __cplusplus
}
#endif

#endif

When the C++ compiler is used, the «__cplusplus» macro is defined.
Now, in such a case, our function's prototype will be wrapped with:

extern "C" {
}

This will tell the C++ compiler that we intend to use everything inside the braces from C code, meaning it will generate symbol names according to C.

So let's recompile our «lib.cpp» file into object code:

g++ -Wall -o lib.o -c lib.cpp

Now, if we run «nm», we can see:

0000000000000100 s EH_frame0
00000000000000eb s L_.str
0000000000000070 s __GLOBAL__I_say_hello
0000000000000148 s __GLOBAL__I_say_hello.eh
0000000000000090 s __Z41__static_initialization_and_destruction_0ii
0000000000000178 s __Z41__static_initialization_and_destruction_0ii.eh
                 U __ZNSolsEPFRSoS_E
                 U __ZNSt8ios_base4InitC1Ev
                 U __ZNSt8ios_base4InitD1Ev
                 U __ZSt4cout
                 U __ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
00000000000001d8 b __ZStL8__ioinit
                 U __ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
                 U ___cxa_atexit
                 U ___dso_handle
0000000000000040 t ___tcf_0
00000000000001a8 s ___tcf_0.eh
0000000000000000 T _say_hello
0000000000000118 S _say_hello.eh

Hurray! The symbol name for our «say_hello» function is now «_say_hello» as with pure C.
It means we are now able to link our object files, in order to produce the executable:

g++ -Wall -o test lib.o main.o

No error here. Our executable was successfully produced, and is working fine!

Of course, when using «extern "C" {}», you can no more use C++ stuff like function's overloading, or namespaces (and of course classes).
But this way, when providing functions implemented in C++, you can make them available to C code, and so to Objective-C as well.

Comments

Author
Carlos
Date
04/09/2012 21:49
Thanks for this very illustrative tutorial.

I have a similar situation with my app right now, I have defined it to use objective

-c++ (by modifying the extension of obj-C files to .mm), and when I try to build it , I get the same issue that you mentioned above (__Z9say_hellov), it seems to me that I should not be getting this error and I don't know what to do to correct the problem.

I would very much appreciate any ideas.

Thanks
Author
Alex
Date
01/14/2013 10:30
Thank you very much for this article!
Author
Scott
Date
04/02/2013 15:54
This is one of the best articles I've ever read, not a joke.
Author
Qadeer
Date
05/29/2013 14:25
Excellent... saved me when it was most needed.. thanks a ton
Author
Anon Anonsson
Date
06/24/2013 22:48
Very nice tutorial, thanks.
Author
Toltori
Date
09/05/2013 03:18
Simple but good thesis.

=======================
1. Title.
"Mixing C++ with C/Objective-C"
2. Point at issue.
Solution to fix the issue of compiling c++ code for c or obective-c project.
3. Solution.
extern "C".
4. Inadequateness.
Can't use c++ stuff.
=======================

Thanks for your good thesis.
Author
Sam
Date
03/11/2014 05:43
I've a same situation in which I need to use a .a c++ library (don't have any idea what is the code in that library) with a header file having some methods declared in it (Probably definitions of methods will be in that library). Now what I need to do is to call these methods from my objective c class. for this I've done following things:

1. changed the extension of my view controller class from .m to .mm
2. set my 'other C++ flags' in build settings to objective-c++

still I'm not able to use that library.What can be mistake here,please suggest...
Author
dmigous
Date
09/28/2014 01:46
>>> A function (or method) can have multiple implementations, as long as there is a difference in the return type and/or the arguments.

C++ doesn't allow to overload function by return type
Author
Tariq
Date
09/28/2014 01:46
very well articulated, thank you.

Add a comment