Reputation: 26259
Help me out here, because I'm half convinced I can't do what I want and half convinced there should be a suitable workaround.
I have a DLL that's implemented in C++ and so exports some classes to other C++ modules that link to it. That's fine. Now I want to link to this DLL from a C module (another DLL), so I will provide a "flattened" C interface and handle the C++ stuff internally. That's also fine.
The problem is that I want to supply this to C or C++ clients as a single .h and associated .lib. So I have something similar to the following in my DLL:
#ifdef DLL_EXPORTS
#define DLL_API __declspec(dllexport)
#else
#define DLL_API __declspec(dllimport)
#endif
// export a class for the C++ clients
class DLL_API CExportedClass
{
public:
CExportedClass();
// etc. etc.
};
// export flattened C interface for non-C++ clients
#ifdef __cplusplus
extern "C" {
#endif
DLL_API void DoSomethingInternally(); // i.e. implementation uses CExportedClass
#ifdef __cplusplus
}
#endif
Of course, this works fine when imported into a C++ module, but it fails to compile when imported into a C module because it doesn't recognise the class
declaration.
So am I wrong to think I can even do this? Do I need to split into two headers? Is it correct and acceptable to use #ifdef __cplusplus
around the class
declarations (or some other kind of #ifdef
)?
Really struggling for a "clean" answer here.
Upvotes: 3
Views: 1271
Reputation: 18431
You may use one header or multiple header, what wouldn't matter. But you must export all C++ stuff as C++ stuff, and all C stuff as C stuff. Don't mix as Hans has recommended - it wont work anyhow.
List out all C functions and put them in "C" boundary, in one separate header, or in just one header. If you are putting C and C++ in on header, just control the compilation (for the client), by using __cplusplus
symbol.
Upvotes: -1
Reputation: 14658
There are couple of articles on MSDN about mixing C and C++:
http://msdn.microsoft.com/en-us/library/aa270933%28v=vs.60%29.aspx
http://msdn.microsoft.com/en-us/library/s6y4zxec%28v=vs.60%29.aspx
I think you can simply take a look at windows.h or similar headers, they works fine for both C and C++ without any problems.
Basically this is how it works:
At the very beginning of header file
#ifndef _MYHEADER__H
#define _MYHEADER__H
#ifdef __cplusplus
extern "C" {
#endif
//Decalrations
//........
//........
//Bottom of your header
#ifdef __cplusplus
}
#endif
#endif
So your header should looks like this:
#ifdef DLL_EXPORTS
#define DLL_API __declspec(dllexport)
#else
#define DLL_API __declspec(dllimport)
#endif
#ifdef __cplusplus
//This part of header is not visible for ANSI C compiler
// export a class for the C++ clients
class DLL_API CExportedClass
{
public:
CExportedClass();
// etc. etc.
};
#endif
#ifdef __cplusplus
extern "C" {
#endif
DLL_API void DoSomethingInternally(); // i.e. implementation uses CExportedClass
#ifdef __cplusplus
}
#endif
This is how it looks for ANSI C compiler:
#ifdef DLL_EXPORTS
#define DLL_API __declspec(dllexport)
#else
#define DLL_API __declspec(dllimport)
#endif
DLL_API void DoSomethingInternally();
This is how it looks for C++ compiler:
#ifdef DLL_EXPORTS
#define DLL_API __declspec(dllexport)
#else
#define DLL_API __declspec(dllimport)
#endif
class DLL_API CExportedClass
{
public:
CExportedClass();
// etc. etc.
};
extern "C" {
DLL_API void DoSomethingInternally();
}
However, you declare class in your header, so C compiler will not be happy with this, you should place it out of "C" declarations.
Take a look here:
http://www.parashift.com/c++-faq/mixing-c-and-cpp.html
Upvotes: 5
Reputation: 941635
The answer is in your question, if __cplusplus isn't defined then you don't want the compiler to see the C++ declarations:
#ifdef __cplusplus
// C++ declarations here
#endif
Putting it all in one .lib file is a bit trickier, you cannot link a DLL. You could however run lib.exe to merge the import libraries of the C and C++ projects. Never actually tried that but it should work. What will certainly work is mixing both the C and C++ source code files in a single project and generate a single DLL. Which is probably what you should pursue, your client is going to be confuzzled by a single .lib requiring two DLLs to be deployed. Also a hint that you probably shouldn't do this in the first place.
Upvotes: 1