Roger Rowland
Roger Rowland

Reputation: 26259

Can I mix C and C++ exports in a single DLL header?

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

Answers (3)

Ajay
Ajay

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

rkosegi
rkosegi

Reputation: 14658

There are couple of articles on MSDN about mixing C and C++:

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

Hans Passant
Hans Passant

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

Related Questions