Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

farmerdoug

macrumors 6502a
Original poster
Sep 16, 2008
541
0
I have two programs- one written in C, one in C++. I need to imbed the C++ code into the C program.
Can I do this? How?

Thanks?
 

Mac_Max

macrumors 6502
Mar 8, 2004
404
1
http://stackoverflow.com/questions/199418/using-c-library-in-c-code

http://www.parashift.com/c++-faq-lite/mixing-c-and-cpp.html#faq-32.6

The real important part is this:

Code:
extern "C" int C_Wrapper_Function(char *bar)
{
    return Actual_C_Plus_Plus_Function(std::string(bar));
}

In your C++ code you have to create a C API. Usually when I do similar things on the PC side I compile my "alien" code into a DLL and link it into my program. It keeps me sane. That might not be necessary when mixing C & C++ however (usually I mix Standard C++, C++/CLI, WPF C#, and Silverlight C#, together depending on the project, which has its own set of complications).

The Stack Overflow link has some info for manipulating your objects as well.
 

farmerdoug

macrumors 6502a
Original poster
Sep 16, 2008
541
0
I'm off to a bad start. This in the header file
extern "C" float * shift(float *five)
{
float array[9];
return array;
}

produces ./include/pcxp.h:193: error: expected identifier or '(' before string constant
make: *** [pcxp] Error 1

Something stupid?

----------

Ok. got around that.
 

farmerdoug

macrumors 6502a
Original poster
Sep 16, 2008
541
0
prototype in code.c
#ifdef __cplusplus
extern "C" void shift(float *nine, float *twentyfive);
#endif


new routine in code.h

#ifdef __cplusplus
extern "C" void shift(float *nine, float *twentyfive)
{
#include "nr3.h"
#include "interp_1d.h"
#include "interp_linear.h"
#include "interp_2d.h"
#include "LUdcmp.h"
#include "krig.h"


int i;
for (i = 0; i < 9; i++)
nine = i;
}
#endif

call in separate function

int weightersum_cubeextract()
{

float *shiftedarray, *arraytobeshifted;

shiftedarray = (float*)calloc(9, sizeof (float));
arraytobeshifted = (float*)calloc(25, sizeof (float));

shift(shiftedarray, arraytobeshifted);
for (i= 0; i < 9; i++)
printf("%f \n", shiftedarray);

...
}

Error

pcxp.c: In function 'weightedsum_cubextract':
pcxp.c:2882: warning: implicit declaration of function 'shift'
Undefined symbols:
"_shift", referenced from:
_weightedsum_cubextract in ccmzV96Z.o
ld: symbol(s) not found
collect2: ld returned 1 exit status
make: *** [pcxp] Error 1
 

Mac_Max

macrumors 6502
Mar 8, 2004
404
1
I'm getting the idea you're trying to compile the C++ cpp files from a C compiler right (that is to say, GCC without C++ support turned on)? You need to compile the C++ file as a library and link the library and program together.

When I get home I'll try to do it on the Mac side of things (since its not the same as doing it in Visual Studio) so I can be more helpful.
 

farmerdoug

macrumors 6502a
Original poster
Sep 16, 2008
541
0
thanks
would really appreciate it.
Here's the make file I am using.


#Makefile for the Project 1640 data pipeline

PIPELINEPATH = PIPELINEDIR=.
DATAPATH = ROOTDATADIR=/DATA0/PHASE2DATA
LIBRARYPATH = LIBRARYDIR=./LIBRARY

CC = gcc -arch x86_64
CFLAGS = -Wall -g -O1
IDIR = ./include
LIBS = -lm -lcfitsio -lgsl -lgslcblas -lmpfit -lfftw3

EXECS = pcxp
OBJS = pcxp.o

pcxp: pcxp.c
${CC} ${CFLAGS} -I${IDIR} -D${PIPELINEPATH} -D${DATAPATH} -D${LIBRARYPATH} pcxp.c ${LIBS} -o pcxp
# ${CC} ${CFLAGS} -I${IDIR} -DMEMWATCH -D${PIPELINEPATH} -D${DATAPATH} -D${LIBRARYPATH} pcxp.c memwatch.c ${LIBS} -o pcxp

all: ${EXECS}

clean:
rm -f ${OBJS} ${EXECS}
 

Sander

macrumors 6502a
Apr 24, 2008
521
67
Farmerdoug, you have #ifdef'ed the entire implementation of the shift() function. Looking at your error code, it seems you're calling it in a C file, where __cplusplus will not be defined. Your compiler has never seen the implementation of shift() at all. The normal way of doing it is this:

In shift.h:
Code:
#ifdef __cplusplus
extern "C" {
#endif

// your prototypes here, including shift:
void shift(float *nine, float *twentyfive);

#ifdef __cplusplus
} // to balance the opening brace above
#endif

In shift.c:
Code:
#include "shift.h"

void shift(float *nine, float *twentyfive)
{
    // implementation of shift()
}

In MyProgram.cpp:
Code:
#include "shift.h"

int main(void)
{
    float nine[9];
    float twentyfive[25];
    shift(nine, twentyfive);

    return 0;
}
 

farmerdoug

macrumors 6502a
Original poster
Sep 16, 2008
541
0
Okay.
So I did what you said without any C++ code. There were no problems.
Then moved a copy of it to my include folder and I tried to include it.
As probably know, it didn't work. How do I add all the include files that are required by iostream?
 

farmerdoug

macrumors 6502a
Original poster
Sep 16, 2008
541
0
my header file now has

#include "iostream"
#include "ios"
#include "streambuf"
#include "istream"
#include "ostream"
#include "__config"
#inlcude "__locale"
#include "iostream"

lots of errors from the include files
for example
./include/__config:259: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'std'
./include/__config:274: error: expected '=', ',', ';', 'asm' or '__attribute__' before '<' token
./include/__config:275: error: expected '=', ',', ';', 'asm' or '__attribute__' before '<' token
./include/__config:276: error: expected '=', ',', ';', 'asm' or '__attribute__' before '<' token
In file included from ./include/ios:215,
from ./include/iostream:38,
from ./include/cppheader.h:9,
from pcxp.c:12:
./include/iosfwd:94: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'std'
In file included from ./include/ios:216,
from ./include/iostream:38,
from ./include/cppheader.h:9,
from pcxp.c:12:
./include/__locale:15:18: error: string: No such file or directory

----------

jiminaus

I can't find this on the thread.
When you compile the C file, use gcc. When you compile the C++ file, use g++ instead.

Never-the-less, in the make file I have to first compile by C++ code with g++ then link the .o file to the C code with gcc?
 

gnasher729

Suspended
Nov 25, 2005
17,980
5,565
Let's start with the basic principles:

You have a C compiler, and a C++ compiler. The C compiler compiles .c files, and the C++ compiler compiles .cpp files. .c files cannot call C++ functions, but .cpp files can contain C functions, and the C functions inside a .cpp file _can_ call C++ functions.

So if you want to call C++ code from a .c file, you need to write a write a C function that calls the C++ code inside a .cpp file. And you need a header file that can be read from .cpp and from .c files. So first the header file. If you just write for example

Code:
int f (int x);

in a header file then this won't work: The C compiler thinks it is a C function named f, but the C++ compiler thinks it is a C++ function named f. And a C and C++ function are not the same. So instead you write in the .h file:

Code:
#ifdef __cplusplus
extern "C" {
#endif

int f (int x);

#ifdef __cplusplus
}
#endif

When the C compiler compiles it, the 'extern "C" {' and '}' are ignored. Just the declaration of the C function f is compiled. When the C++ compiler compiles it, the 'extern "C" {' and '}' are compiled, and they tell the C++ compiler "this is a C function named f", so now C and C++ agree.

Now you implement the function f. You just add it to a .cpp file that includes the header file. Because f is declared as a C function, the C++ compiler will compile it as a C function, so C code can call it. But because it is compiled by the C++ compiler, and the C++ compiler knows how to call C++ code, the function f can call any C++ code.
 

Mac_Max

macrumors 6502
Mar 8, 2004
404
1
You'll have to correct me again if I'm misreading your posts, but I don't believe you can expose any function that uses IOStream or any of the other C++ STL headers in C, even when obfuscating them through a library with a C API. I think you need to write a wrapper that implements the same functionality using native C functions and use #ifdefs for C & C++ for conditional compilation. I could be wrong but I haven't seen anything in google that says otherwise.

The biggest problem is that even if the gcc can find the libraries and figure out each and every type, it will have no idea how to deal with <<, >>, new, delete, references, some keywords, and a few other things I can't remember.

Assuming you have XCode, I've attached three projects. One generates a static library, one is a C++ command line test, and the third is a C command line test. The command line apps do the same thing, just one in C++ and the other in C. They demonstrate the basic way to wrap a C++ class with a C API so you can use the class. I used this link for help when writing it:

http://developers.sun.com/solaris/articles/mixing.html#iostream

I'll paste the code of the C++ library and the C test code so everyone can see it without downloading:

CPPClass.h:
Code:
#ifndef CPPLib_CPPClass_h
#define CPPLib_CPPClass_h
#ifdef __cplusplus

class CPPClass{
    
public:
    static void StatPlusPlus(int* aNum);
    void PlusPlus(int* aNum);
    
};
# else
//This is very important!  Also seen as extern struct <identifier> <identifier> 
struct CPPClass;

#endif

//C API

#ifdef __cplusplus
extern "C" {
#endif

    /* ANSI C prototypes */
#if defined(__STDC__) || defined(__cplusplus)
    extern void c_StatPlusPlus(int*);
    extern void c_PlusPlus(struct CPPClass*, int*);   

#endif
    
#ifdef __cplusplus
}
#endif

//C and C++ friendly

#ifdef __cplusplus
extern "C" {
#endif
    
void GlobalPlusPlus(int* aNum);

#ifdef __cplusplus
}
#endif
#endif

CPPClass.cpp:
Code:
//
//  File.cpp
//  CPPLib
//
//  Created by Max on 1/17/12.
//  Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//

#include "CPPClass.h"

void CPPClass::StatPlusPlus(int* aNum){
    (*aNum)++;
}


void CPPClass::PlusPlus(int* aNum){
    (*aNum)++;
}

 /* ANSI C prototypes */

void c_StatPlusPlus(int* Var)
{
    CPPClass::StatPlusPlus(Var);
}

void c_PlusPlus(struct CPPClass* Target, int* Var)
{
    Target->PlusPlus(Var);
}

void GlobalPlusPlus(int* aNum){
    (*aNum)++;
}

Inside the C test program I've included alongside main: libCPPLib.a (the output from the C++ static library XCode project) and the header CPPClass.h.

main.c:
Code:
#include <stdio.h>
#include "CPPClass.h"

int main (int argc, const char * argv[])
{

    //ported from my CPP Test
    int TestInt = 10;
    
    //Static
    c_StatPlusPlus(&TestInt);
    printf("%d \n", TestInt);
    
    //Class
    //Important! Must be a pointer to CPPClass
    //CPPClass is an incomplete specification and the C compiler won't know what to do with it.
    //Thankfully it always knows what to do with a pointer!
    struct CPPClass* CP;
    c_PlusPlus(CP, &TestInt);
    printf("%d \n", TestInt);
    
    //Global
    GlobalPlusPlus(&TestInt);
    printf("%d \n", TestInt);
    
    printf("Hello, World!\n");
    return 0;
}

Sorry for the length, if MR supported the
tags I would have used them.
 

Attachments

  • C_CPP test.zip
    143.8 KB · Views: 89
Last edited:

Mac_Max

macrumors 6502
Mar 8, 2004
404
1
Btw, is there any reason you have to use a C compiler? Could you just use a C++ compiler but write everything the same as you would in C? That would solve 100% of your issues.
 

farmerdoug

macrumors 6502a
Original poster
Sep 16, 2008
541
0
Sorry, I haven't gotten back to you guys. I found a work around and been pursuing the main task ever since. Please don't think the effort was wasted. I did learn some new tricks.
 

Mac_Max

macrumors 6502
Mar 8, 2004
404
1
No worries, I got to teach myself how to use/include C/C++ libraries in XCode haha. Did you end up getting the libraries with STL references to work?
 

farmerdoug

macrumors 6502a
Original poster
Sep 16, 2008
541
0
No even simpler. I remembered.
In previous work, I started with a 2-d spline fit from an old copy of Numerical Recipes in C. It was written in C but then I switched to a different fit from a newer edition of the book. I switched because the new code could use uneven point spacing. It was written in C++.
This time I needed a 2-d spline fit for someone else's existing C code and went straight to the C++ fit. After a day of trying to put them together, I remembered the old C code and because I was using even spacing I no longer had to worry about C++.
Thanks again for your help.

PS. I learned Tuesday that C++ was an invention from the evil Microsoft Empire. I wonder why Numerical Recipes in C switched to C++
 

jiminaus

macrumors 65816
Dec 16, 2010
1,449
1
Sydney
I learned Tuesday that C++ was an invention from the evil Microsoft Empire.

Where did you learn that?! What bollox! Bjarne Stroustrup started developing C++ in 1979 at Bell Labs. In 1985, he published the first edition of The C++ Programming Language. Microsoft didn't release its first C++ compiler until 1992. AFAIK Bjarne Stroustrup has never worked for Microsoft.

Managed C++ is a whole other story.
 
Last edited:

jiminaus

macrumors 65816
Dec 16, 2010
1,449
1
Sydney
I learned Tuesday that C++ was an invention from the evil Microsoft Empire.

Apparently this is enough of a misconception that Bjarne Stroustrup put it on his FAQ.

C++ is designed by Microsoft? No. I originally designed and implemented C++ and together with the ISO C++ standards committee refined its definition. Microsoft has taken an active and largely positive role in this standardization - as has Apple, GNU, IBM, Sun, and many others. Like others - e.g. Apple - Microsoft tries to help/lock-in their users with proprietary extensions, (in particular, Microsoft C++/CLI).
 

farmerdoug

macrumors 6502a
Original poster
Sep 16, 2008
541
0
I stand corrected. Never having found a use for OOP, anything I can blame on Bill Gates, I can. The time wasted dealing with windows and windows machines has left me with a permanent dislike for the man, the company and its products.
 

Sander

macrumors 6502a
Apr 24, 2008
521
67
You'll have to correct me again if I'm misreading your posts, but I don't believe you can expose any function that uses IOStream or any of the other C++ STL headers in C, even when obfuscating them through a library with a C API.

Yes you can, as long as the function prototype doesn't contain any C++ types. For example, it's perfectly fine to have

Code:
double f(int i)
{
    std::vector<double> values(some_cpp_function());
    return values[i];
}
don't mind the crappy code itself; I just wanted to point out that in the implementation of the function, you're free to use as much C++ as you like. You will still be able to call this function from C.

----------

I stand corrected. Never having found a use for OOP, anything I can blame on Bill Gates, I can. The time wasted dealing with windows and windows machines has left me with a permanent dislike for the man, the company and its products.

It's not like Bill Gates (or anyone else at Microsoft) invented OOP...
 

Mac_Max

macrumors 6502
Mar 8, 2004
404
1
Yes you can, as long as the function prototype doesn't contain any C++ types. For example, it's perfectly fine to have

Code:
double f(int i)
{
    std::vector<double> values(some_cpp_function());
    return values[i];
}
don't mind the crappy code itself; I just wanted to point out that in the implementation of the function, you're free to use as much C++ as you like. You will still be able to call this function from C.


Right I know about that. I thought the OP was trying to directly import headers from C++ and do something like:

Code:
void foo(std::string bar)
{
        cppFoo(bar);
}

Before I knew where he stood on that issue, I thought he was trying to do something COM style but without all the "magic" that lets you use non-native but COM friendly types in any Windows codebase. Doesn't sound like he's much of a MS fan though haha.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.