views:

75

answers:

3

I have a piece of C code that is used from a C++ function. At the top of my C++ file I have the line: #include "prediction.h"

In prediction.h I have this:

#ifndef prediction  
#define prediction  

#include "structs.h"  

typedef struct {  
    double estimation;  
    double variance;  
} response;

response runPrediction(int obs, location* positions, double* observations,
                        int targets, location* targetPositions);

#endif

I also have prediction.c, which has:

#include "prediction.h"  

response runPrediction(int obs, location* positions, double* observations,
                        int targets, location* targetPositions) {  
    // code here  
}

Now, in my C++ file (which as I said includes prediction.h) I call that function, then compile (through Xcode) I get this error:

"runPrediction(int, location*, double*, int, location*)", referenced from:
mainFrame::respondTo(char*, int)in mainFrame.o
ld: symbol(s) not found
collect2: ld returned 1 exit status

prediction.c is marked for compilation for the current target. I don't have any problems with other .cpp files not being compiled. Any thoughts here?

+4  A: 

Likely the name of the function is being mangled*. You need to do the following:

extern "C" response runPrediction(int obs, location* positions,
                   double* observations, int targets, location* targetPositions);

Which tells it to treat it as a C function declaration.

*C++ mangles function names to give them unique names during the linking phase, for function overloading. C has no function overloading so does no such thing.


Just so you know, you can also make an extern "C" block, if you have multiple things to extern:

extern "C"
{
    response runPrediction(int obs, location* positions,
                   double* observations, int targets, location* targetPositions);

    // other stuff
}

And like Paul suggests, to allow the header to be used in both use __cplusplus to condition it:

#ifdef __cplusplus
    #define EXTERN_C extern "C"
#else
    #define EXTERN_C
#endif

EXTERN_C response runPrediction(int obs, location* positions,
                   double* observations, int targets, location* targetPositions);
GMan
For a mixed C/C++ project it's better to bracket `extern "C" {`/`}` with `#ifdef __cplusplus`/`#endif` so that the header can be #included by both C and C++ source files
Paul R
@Paul: I forgot about that detail. :) If you don't mind, I'm going to add that.
GMan
I'm not sure what this is about. I put `extern "C" response runPrediction...` and I get this error: `expected identifier or '(' before string constant`
jfm429
@jfm429: Was that being compiled in C or C++? C has no `extern "C"`, hence the preprocessor define to toggle it.
GMan
Huh, the conditional extern works. Is it possible that somehow it was being compiled once as C, and once as C++? Anyway, I put the conditional ifdef in and it solved the problem. Thanks!
jfm429
@jfm429: yes, it gets compiled as C when you compile prediction.c (which #includes prediction.h) and again as C++ whenever you #include prediction.h in a C++ source file.
Paul R
+3  A: 

Change prediction.h so that it looks like this:

#ifndef prediction  
#define prediction  

#include "structs.h"  

#ifdef __cplusplus
extern "C" {
#endif

typedef struct {  
    double estimation;  
    double variance;  
} response;

response runPrediction(int obs, location* positions, double* observations,
                        int targets, location* targetPositions);

#ifdef __cplusplus
}
#endif

#endif
Paul R
It would be nice if I could accept multiple answers; this as well as the previous answer both helped. Thanks guys!
jfm429
A: 

Is 'prediciton' realy C and not C++? You will have different default compilations based on the file extension, GMan covers this.

If it is ment to be C++ and you change the file name, I would still sugest that runPrediction should be marked extern in the header, it is not defined in the local C++ module defining class mainFrame.

Greg Domjan