views:

88

answers:

4

Lets say I have a C++ program and I want to call functions from a C object file in it. The constraint is that I'm not allowed to make any changes to the C source files.

In this case I would include the C header as extern "C" in my C++ file, call the function, compile the C object using gcc -c, and pass the result to g++ along with the actual C++ sources.

I guess what I would also do is to put the C-header #include inside a named namespace block in the C++ file, as to keep the local namespace clean (who knows what other fancy stuff there is in the .h file).

What now if I need to call functions from two C object files. Lets say that they have different signatures. But there are also some duplicate functions in the object files. Wouldn't my linker blow up at this point if I tried to pass both objects to g++ at the same time? Same for globals.

Again: I'm not allowed to change ANY of the C sources. Else I would just rename the .c files to .cxx, wrap their contents and the contents of the corresponding headers inside namespace bla { } and feed everything to g++.

(Yes, C is not a subset of C++, as has already been mentioned in one of the comments)

+2  A: 

Your last paragraph has a good solution - why not make a C++ file something like this:

namespace c_namespace_1 {
    #include "CFile1.c"
}

namespace c_namespace_2 {
    #include "CFile2.c"
}

And so on.... then you could compile this file as C++ and not have to modify the original sources.

Carl Norum
Likely the files are not C++; they're C. **C is not a subset of C++** and there's no reason to expect a C source file to compile as C++ code.
R..
Amazing and worrying at the same time that I was unable to come up with that myself. Will try. Thanks.
niscy
@R.: In this case, they are a subset of C++. But better solutions are always welcome.
niscy
@R: Is that really worth a downvote? It's certainly has a 90% or better likelihood of working, and in fact the OP says it's a good option. @niscy, as far as better solutions, your linker may in fact support multiply-defined symbols. Older linkers in particular tend to have support for this sort of situation, from back when getting static libraries delivered to you by a vendor was more common.
Carl Norum
Since OP liked it, I removed the down-vote. I assumed the OP had already tried this since it was mentioned, in which case the answer was wrong and redundant.
R..
I do question your 90% though. Basically any good-practices C code that uses `malloc` would fail since C++ does not allow implicit conversion of `void *`.
R..
@Carl, I didn't down-vote it, but I believe it's worth the one it already got. Your suggestion wouldn't work in the general case. The OP said he couldn't edit the C sources, so there is good reason to believe they won't compile as C++. Meanwhile, in the future, other readers will consult your answer and get the idea they should follow it. As a consequence, they will edit their C files in order to introduce C++-isms. Converting C to C++ without a real need is bad.
Heath Hunnicutt
+1  A: 

You could bring the C executable codes in as individual binary data files and handle the function pointer casting yourself - basically do the linker's job for it. If the binary directly wouldn't work, get the assembler output of the C files and wrap them in functions similiar to the above suggestion of namespaces.

Michael Dorgan
A: 

How about compile each C subsystem to its own LIB file, then compile a separate C++ LIB file that includes the appropriate C LIB and provides wrapped function calls to only the C functions in its .LIB

ie:

file1.c => file1.lib
file2.c => file2.lib

Wrapper1.cpp + file1.lib => Wrapper1.lib
Wrapper2.cpp + file2.lib => Wrapper2.lib

Application.cpp + Wrapper1.lib + wrapper2.lib => Application.exe

Note that this off the top of my head and I have no idea if the linker will still go boom

Of course you could compile Wrapper1 and Wrapper2 to dll's instead of Lib's and that would ensure the linker doesn't go boom!

Peter M
A: 

This is pretty hacky, but one solution is to rename the function(s) in question via macros, so that they have different names as far as the linker is concerned.

For example, if you have too functions called foo, one of which takes an int and the other of which takes a double, in files IntFoo.c and DoubleFoo.c, you can compile them like this:

cc -Dfoo=IntFoo -o IntFoo.o IntFoo.c
cc -Dfoo=DoubleFoo -o DoubleFoo.o DoubleFoo.c

Then in your C++, you can do this:

#define foo IntFoo
extern "C" {
    #include "IntFoo.h"
}

#define foo DoubleFoo
extern "C" {
    #include "DoubleFoo.h"
}

#undef foo

There are lot of caveats here: you have to ensure that the symbol foo is used only as the name of the function you want, you have to ensure that you define the macros appropriately everywhere that the symbol foo is used. If there are duplicate symbols, you have to define macros for those as well.

It is probably a much better solution to just fix the C files.

Kristopher Johnson