C++ 支持函數重載,編譯器通過名稱修飾將函數簽名編碼進符號名:void foo(int, float) → _foo_int_float。C 語言無重載,符號名僅為 _foo。直接混用會導致鏈接階段找不到符號。
GetProcAddress/DllImport 按名查找#ifndef MYLIB_H
#define MYLIB_H
#ifdef __cplusplus
extern "C" {
#endif
// 函數聲明
int add(int a, int b);
void init();
#ifdef __cplusplus
}
#endif
#endif
extern:聲明符號具有外部鏈接,可跨文件訪問(對應 static 內部鏈接)"C":指定C 語言鏈接規約(無名稱修飾)| 場景 | C++ 頭文件 | C 實現文件 |
|---|---|---|
| C++ 調用 C | extern "C" { #include "c.h" } | 普通 extern int add(); |
| C 調用 C++ | extern "C" int add(); | extern int add();(不可含 extern "C") |
| C++ 實現供 C 用 | extern "C" int add(); | extern int add(); |
| C 實現供 C++ 用 | extern "C" { #include "c.h" } | 普通實現 |
將函數/類/變量放入 DLL 導出表,供外部調用。等價於 .def 文件 EXPORTS 節。
__declspec(dllexport) int add(int a, int b); // 導出函數
__declspec(dllexport) class MyClass { ... }; // 導出整個類
#ifdef MYLIB_EXPORTS // DLL 端定義此宏
#define MYLIB_API __declspec(dllexport)
#else // 客戶端不定義
#define MYLIB_API __declspec(dllimport)
#endif
MYLIB_API int add(int a, int b);
MYLIB_API class MyClass { ... };
導出類時,靜態成員變量必須在客戶端正確導入:
// MyClass.h
class MYLIB_API MyClass {
static int s_value; // 靜態成員
public:
static int getValue();
};
// MyClass.cpp (DLL 端)
int MyClass::s_value = 0; // 定義
// 客戶端若無 dllimport,鏈接時找不到 s_value!
原因:靜態成員實際在 DLL 數據段,客戶端需通過 dllimport 正確解析地址。類導出宏自動處理成員函數,但靜態數據成員需顯式 dllimport。
// MathLib.h
#ifdef MATHLIB_EXPORTS
#define MATH_API __declspec(dllexport)
#else
#define MATH_API __declspec(dllimport)
#endif
extern "C" MATH_API int Add(int a, int b);
extern "C" MATH_API int Sub(int a, int b);
// MathLib.cpp
#include "MathLib.h"
extern "C" MATH_API int Add(int a, int b) { return a + b; }
extern "C" MATH_API int Sub(int a, int b) { return a - b; }
public static class MathLib {
[DllImport("MathLib.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int Add(int a, int b);
[DllImport("MathLib.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int Sub(int a, int b);
}
// 使用
int sum = MathLib.Add(10, 20); // 30
CallingConvention.Cdecl:匹配 C/C++ 默認調用約定(調用方清棧)Dependency Walker 確認導出符號名無修飾(Add 而非 _Add@8)| 錯誤 | 原因 | 解決 |
|---|---|---|
| Unresolved external symbol | 缺少 dllexport / 宏未定義 | 檢查 MYLIB_EXPORTS 定義、頭文件包含順序 |
| BadImageFormatException | x86/x64 不匹配 | 統一編譯目標平台 |
| EntryPointNotFound | 名稱修飾 / 拼寫錯誤 | 加 extern "C"、用 Dependency Walker 查導出名 |
| 靜態成員訪問失敗 | 缺少 dllimport | 類導出宏需覆蓋靜態數據成員 |