Xavier
Xavier

Reputation: 9079

How do you call a C function from C++ code in the iPhone?

I added the line extern "C" void perlinTest(void); to a C++ header along with the include of the c header file hoping that was all I needed but the compiler complains:

Undefined symbols for architecture i386:
  "perlinTest()", referenced from:
      CreateRenderer3(IResourceManager*) in Renderer.o

Upvotes: 1

Views: 251

Answers (4)

Miguel Grinberg
Miguel Grinberg

Reputation: 67547

One trick you can use to debug this is to introduce an intentional error in your perlinTest() function. Then build your app and see if the compiler reports the error. If the app compiles anyway, then your problem is that the file that has this function is not part of the target you are building.

Also note that the error that you pasted is for a i386 architecture, so it can't be iPhone. You are probably building for the iPhone simulator instead.

Edit: next step would be to check that the link command issued by Xcode includes the .o that has the C function. If it does, then you should dump the contents of the .o file with the nm utility, to see what the function name looks like in the .o.

Upvotes: 0

NSGod
NSGod

Reputation: 22968

Have you actually implemented void perlinTest(void) anywhere?

Initially, you'll likely be able to merely declare the function without actually having to implement it. If none of your other classes/objects actually call perlinTest(), Xcode will gladly build and run your app, and not issue any errors. Since perlinTest() isn't actually referenced from anywhere, it doesn't care that the function isn't actually implemented.

As soon as you attempt to call perlinTest() from one of your other classes (like from CreateRenderer3(IResourceManager*) in Renderer.o), the linker will want to make sure that symbol can be resolved, and if you haven't actually implemented a barebones definition of it (see below), then you'll likely get an error like the one you got.

A minimal implementation like the following should prevent the linking error:

void perlinTest(void) {

}

Upvotes: 0

zneak
zneak

Reputation: 138261

Your C++ code needs to be aware that the function is a C function. To do so, you need to declare it this way:

extern "C" [prototype];

A realistic example for your situation would be:

extern "C" void perlinTest();

The reason for this is that C++ function names are mangled to something that tells about the types of the parameters. At the lowest level, this is what allows overloading: it never really is legal to have two visible symbols that share the same name, so C++ allows them by embedding markers that indicate the types of the parameters in the function names. For instance, void perlinTest() gets mangled as _Z10perlinTestv on my Lion box with g++ (and probably clang++), though this is ABI-specific and will not necessarily be the same on other platforms.

However, C doesn't support overloading, and functions aren't subject to name mangling, so when your C++ code tries to call one, it needs to know that it must not use a mangled name. This is what extern "C" tells the compiler.

If your header files need to be readable from both C and C++, the common practice is to wrap them in an extern "C" block (extern "C" { /* declarations */ }) itself wrapped in an #ifdef __cplusplus preprocessor directive (so the C code doesn't see the extern "C" code).

#ifdef __cplusplus
extern "C" {
#endif

/* header body */

#ifdef __cplusplus
}
#endif

Upvotes: 1

kellogs
kellogs

Reputation: 2867

If it is not a library, you do not need any extern C. Iwould be turning to the .c file extensions and how your compiler is configured to recognize it (looks like not as .c code)

Upvotes: 0

Related Questions