__declspec(dllexport) is a Microsoft-specific extension to the C and C++ languages used to mark functions, variables, or entire classes for export from a dynamic-link library (DLL). This tells the compiler and linker to make the symbol's definition—its name and address—available to other executables and DLLs that want to use it. Essentially, it is the mechanism that makes your code accessible to the outside world when it is compiled into a DLL.
Core concepts
To understand the purpose of __declspec(dllexport), it's helpful to know the difference between building a program as a single executable and as a modular set of DLLs.
- Monolithic executable: In a single
.exefile, all function and variable definitions are compiled and linked together. The compiler can directly resolve all symbols during the build process. - Modular DLLs: When you split code into a DLL and a separate executable that uses it, the executable no longer has direct access to the definitions within the DLL. The linker needs a way to resolve these external references at runtime.
__declspec(dllexport) and its counterpart, __declspec(dllimport), are the solution to this problem on the Windows platform.
__declspec(dllexport): Used when building the DLL. It instructs the linker to place the marked symbols into the DLL's export table and to generate an associated import library (.lib). This import library contains the information necessary for other modules to link with the DLL.__declspec(dllimport): Used when consuming the DLL. It informs the compiler that a symbol's definition resides in a separate DLL. This allows the compiler to generate more efficient code that references the DLL's import table, avoiding an extra layer of indirection.
How it works: The role of the linker
During the build process, the compiler processes the __declspec(dllexport) attribute.
- Symbol decoration: For C++ symbols, the compiler generates a "decorated name" or "name mangling," which encodes information about the function, such as its parameters and namespace. For C functions, the
extern "C"linkage specifier is used to prevent this name decoration. - Export table creation: The linker receives instructions from the compiler to create an export table within the final
.dllfile. This table is a list of the public symbols that other applications can access. - Import library generation: The linker also creates an import library (
.libfile). This static library contains the information that other applications will use to find the symbols in the DLL.
Common usage pattern with macros
Since the same header file is often used for both building the DLL and for client applications that consume it, a preprocessor macro is the standard practice. This allows the header to adapt its behavior depending on the build context.
Header file (e.g., my_library.h)
#pragma once
#ifdef MY_LIBRARY_EXPORTS
#define MY_API __declspec(dllexport)
#else
#define MY_API __declspec(dllimport)
#endif
// Exported function
MY_API int add(int a, int b);
// Exported class
class MY_API MyClass {
public:
void doSomething();
};
Use code with caution.
Implementation file (e.g., my_library.cpp)
#include "my_library.h"
int add(int a, int b) {
return a + b;
}
void MyClass::doSomething() {
// ...
}
Use code with caution.
Client application file (e.g., main.cpp)
#include "my_library.h"
int main() {
int sum = add(5, 7);
MyClass myObject;
myObject.doSomething();
return 0;
}
Use code with caution.
When building the DLL, you define the MY_LIBRARY_EXPORTS preprocessor macro, which causes MY_API to expand to __declspec(dllexport). When building the client application, this macro is not defined, so MY_API expands to __declspec(dllimport).
Exporting classes
Applying __declspec(dllexport) to a class automatically exports all of its members, including its constructors, destructors, and member functions, and related information such as the vtable and Run-Time Type Information (RTTI).
class __declspec(dllexport) MyClass {
// ... all public and private members are exported
};
Use code with caution.
Limitations when exporting classes:
- You cannot apply
__declspec(dllexport)to individual members of a class that is already marked for export. - All base classes in a class hierarchy must also be marked with
__declspec(dllexport). - If a class has virtual functions, all virtual functions must be exported or defined inline to ensure clients have proper access to the vtable.
Alternatives to __declspec(dllexport)
While __declspec(dllexport) is the standard, modern approach on Windows, two older methods exist:
- Module-Definition (
.def) files: These files explicitly list the functions and variables to export. This approach offers more control, such as exporting symbols by ordinal rather than by name, which can slightly improve performance. For C++ functions, you must manually list the decorated names. __exportkeyword: The predecessor to__declspec(dllexport)is now considered obsolete.
Portability and compiler specifics
The __declspec syntax is a Microsoft extension and not part of standard C++. While compilers like GCC and Clang now support it for compatibility with Windows, the standard and cross-platform way to manage symbol visibility is a different process, often leveraging __attribute__((visibility("default"))) on Unix-like systems. This is another reason why using preprocessor macros is important for creating cross-platform code.
Summary: When to use __declspec(dllexport)
- When you are building a library that you want to be shared dynamically by other programs on Windows.
- To export functions, variables, or entire C++ classes from your DLL.
- It is the most convenient method for exporting C++ functions because it automatically handles complex name-mangling schemes.
- It simplifies the build process by removing the need for a separate
.deffile for specifying exports.