PDA

View Full Version : C++ in C




farmerdoug
Jan 17, 2012, 09:26 AM
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
Jan 17, 2012, 09:50 AM
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:



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
Jan 17, 2012, 09:55 AM
Lunch first, then I will try.
Thanks. I may have to get back to you.

farmerdoug
Jan 17, 2012, 11:18 AM
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
Jan 17, 2012, 11:44 AM
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] = 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[i]);

...
}

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
Jan 17, 2012, 03:21 PM
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
Jan 17, 2012, 03:26 PM
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
Jan 17, 2012, 04:13 PM
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:

#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:

#include "shift.h"

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

In MyProgram.cpp:

#include "shift.h"

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

return 0;
}

farmerdoug
Jan 17, 2012, 05:51 PM
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?

jiminaus
Jan 17, 2012, 05:55 PM
Which file is including iostream?

farmerdoug
Jan 17, 2012, 06:15 PM
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
Jan 17, 2012, 06:43 PM
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

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:

#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
Jan 17, 2012, 08:34 PM
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:

#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:

//
// 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:

#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 [spoiler] tags I would have used them.

Mac_Max
Jan 17, 2012, 09:57 PM
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
Jan 18, 2012, 02:47 PM
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
Jan 19, 2012, 12:18 AM
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
Jan 19, 2012, 05:25 AM
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
Jan 19, 2012, 05:41 AM
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++ (http://en.wikipedia.org/wiki/Managed_Extensions_for_C%2B%2B) is a whole other story.

balamw
Jan 19, 2012, 05:44 AM
PS. I learned Tuesday that C++ was an invention from the evil Microsoft Empire.

You appear to be confusing C++ and C#. (C++ ++ ;) )

B

jiminaus
Jan 19, 2012, 06:21 AM
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 (http://www2.research.att.com/~bs/bs_faq.html).


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
Jan 19, 2012, 08:16 AM
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
Jan 23, 2012, 08:53 AM
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


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
Jan 23, 2012, 10:47 AM
Yes you can, as long as the function prototype doesn't contain any C++ types. For example, it's perfectly fine to have


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.[COLOR="#808080"]


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



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.