tags:

views:

161

answers:

11

I have a bunch of C code. I have no intention to convert them into C++ code.

Now, I would like to call some C++ code (I don't mind to modify the C++ code so that they are callable by C code).

class Utils {
public:
    static void fun();
}

class Utils2 {
public:
    static std::wstring fun();
}

If I tend to call them with the following syntax, they wont compiled (I am using VC++ 2008, with C code files with .c extension)

Utils::fun();
// Opps. How I can access std::wstring in C?
Utils2::fun();

Any suggestion?

A: 

C is a subset of C++ .. So u can not call c++ Class members and namespaces in C.

Prav
-1 it is clear that the asker understands this - thus the question
Elemental
A: 

I think the only solution is to wrap them in C style global functions in the C++ code like:

extern "C" int Util2_Fun() { return Util2::Fun(); }

I suppose you could also declare global function pointers as externs using some nasty variation of:

extern int (*Utils2_Fun)()=(int *())(Util2::Fun);

And then call the function pointer directly from the C package using this pointer but there is little to recommend this approach.

Elemental
that need to be extern "C" in the first example, or it will be subject to namemangling.
roe
Thanks, edited as such, my error.
Elemental
+3  A: 

What about a wrapper

extern "C" void Utilsfun(int i){Utils::fun(i);}

Update:

That is how you can call C++ functions from C, but accessing std::wstring from C is a different matter.

If you really wanted to manipulate C++ classes from C code then you could create an API where the classes are operated on with C++ functions, and passed back to C using void pointers. I've seen it done, but it's not ideal

extern "C"
{
void * ObjectCreate(){return (void *) new Object();}
void ObjectOperate(void *object, char *parameter){((Object*)object)->Operate(parameter);}
void ObjectDelete(void *object){delete ((Object*)object);}
}

You will have to be very careful about managing creating and deleting.

David Sykes
How about std::wstring handling?
Yan Cheng CHEOK
extern "C" wchar_t const* Utilsfun(int i){ ...
Chris Becke
@Chris: And who is allocating/deleting the character buffer and how? It is much better to write to a caller-supplied buffer. See [my answer](http://stackoverflow.com/questions/3193020/calling-c-static-member-functions-from-c-code/3193099#3193099).
sbi
But something may go wrong, when the class is having virtual functions, right?
Yan Cheng CHEOK
@Yan I don't see why it should, all the class operations are on the C++ side. They should act as expected
David Sykes
A: 

You can make C++ callable from C by using the extern "C" construct.

Borealid
A: 

The most common solution is to write a C interface to your C++ functions. That is C++ code which are declared using extern "C" { ... }. These wrapper functions are free to call any C++ code they like, but since they're declared extern "C", they won't be subject to name mangling (you can't do namespaces or overloading here).

That ought to be linkable with your C file and you're good to go.

That is, the header file contains

#ifdef __cplusplus
extern "C" {
#endif

  void wrapper1(void);
  int wrapper2(int x);
  char* wrapper3(int y);

#ifdef __cplusplus
}
#endif

The ifdefs are required to shield the C compiler from the extern "C". And you implement those in your C++ source

void wrapper1(void) { Util::funcOne(); }
int wrapper2(int x) { return Util::funcTwo(x); }
char* wrapper3(int y) { return Util::funcThree(y); }
roe
A: 

Create a wrapper function in your C++ code:

extern "C" void Wrapper() {
    Utils2::fun();
}

and then in your C code:

extern void Wrapper();
int main() {
    Wrapper();
    return 0;
}
anon
A: 

If you do as ppl say here (using extern "C") beware that you only pass objects to the C function that would compile in C.

InsertNickHere
+3  A: 
// c_header.h
#if defined(__cplusplus)
extern "C" {
#endif

void Utils_func();
size_t Utils2_func(wchar_t* data, size_t size);

#if defined(__cplusplus)
}
#endif
//eof

// c_impl.cpp
// Beware, brain-compiled code ahead!
void Utils_func()
{
  Utils::func();
}

size_t Utils2_func(wchar_t* data, size_t size)
{
  std::wstring wstr = Utsls2::func();
  if( wstr.size() >= size ) return wstr.size();
  std::copy( wstr.begin(), wstr.end(), data );
  data[wstr.size()] = 0;
  return str.size();
}
//eof
sbi
So, the C caller is responsible to allocate / free memory for wchar_t data?
Yan Cheng CHEOK
This is the way I'd do it too. This kind of caller-allocates style is very common in C libraries.
Owen S.
@Yan: Yes, this is usually the safest. Allocating resources in one DLL and freeing it in another often creates problems. Also, it raises questions of resource ownership.
sbi
But the caller must know the size of the string before calling Utils2_func(). Sometimes we may want to allocate memory in the function and let the caller free it (e.g. strdup).
@lh3: That's why the function returns the size if you pass in too small a buffer. You could call the function upfront `size_t size = Utils2_func(NULL,0);` and have it return the size to you.
sbi
A: 

You won't have any practical use for c++ objects in your C code, so you'll probably want to create some sort of "C Binding" for your C++ code which consists of some number of ordinary functions that are callable from the C, and only return ordinary C data types. Your wrapper functions can then call all sorts of classes and objects, etc. But, they provide a simpler C-Style interface for the objects that you can use from C to bridge the gap. You can also use function pointers in some cases to give the C access to static methods, but it's usually easiest just to create the wrapper, IMHO.

wrosecrans
A: 

You can either write global extern "C" wrapper functions or use function pointers to additionally make static class functions known to C. The C++ code can put these pointers in a global structure or pass them to C while calling a C function as a parameter. Also, you could establish a registry where the C code can request function pointers from C++ by supplying a string id. I've these all these varieties being used.

Peter G.
A: 

If you have control of all of the source, I wouldn't bother trying to keep part of it as C. It should be compilable as C++ (or easily changed to make it so). That doesn't mean you need to rewrite it as C++, just compile it as such. This way you can use whatever parts of C++ make sense. Over time, the C code make turn more C++ like, but this will happen slowly as the need arises.

Of course, if you need it to remain compilable in C for other reasons, this doesn't apply.

KeithB