C/C++导出函数和变量

文章目录

    • 一、导入导出机制
    • [二、 __declspec(dllexport)和 extern "C" __declspec(dllexport)的区别](#二、 __declspec(dllexport)和 extern "C" __declspec(dllexport)的区别)
    • 三、示例

一、导入导出机制

__declspec(dllexport)__declspec(dllimport) 都是在 C/C++ 中用于处理导入和导出函数或变量的修饰符。

1.__declspec(dllexport):当你希望将函数或变量导出到 DLL 中,以供其他程序使用时,你需要使用 __declspec(dllexport) 修饰符来标记这些函数或变量。你可以将它们放在函数或变量的声明之前,以告诉编译器在链接阶段将这些函数或变量导出到 DLL。例如:

cpp 复制代码
// 导出函数到 DLL
__declspec(dllexport) void ExportedFunction();

// 导出变量到 DLL
__declspec(dllexport) int ExportedVariable;
  1. __declspec(dllimport):当你在一个程序中需要使用从 DLL(动态链接库) 中导入的函数或变量时,你需要使用 __declspec(dllimport) 修饰符来声明这些函数或变量是从 DLL 中导入的。你可以将它们放在函数或变量的声明之前,以告诉编译器在链接阶段从 DLL 中获取相应的定义。例如:
cpp 复制代码
// 导入 DLL 中的函数声明
__declspec(dllimport) void SomeFunction();

// 导入 DLL 中的变量声明
__declspec(dllimport) extern int SomeVariable;

需要注意的是,__declspec(dllexport) 修饰符会生成 DLL 的导出表,并使得这些函数和变量可被其他程序使用。而 __declspec(dllimport) 修饰符则用于在其他程序中声明从 DLL 中导入的函数和变量,以便正确地链接和使用它们。

一般情况下,你会使用条件编译来定义这些修饰符,以便在不同的情况下选择性地声明为 __declspec(dllexport)__declspec(dllimport)。例如,在 DLL 的源代码中,你可以使用如下条件编译:

cpp 复制代码
#ifdef MYLIB_EXPORTS
    #define MYLIB_API __declspec(dllexport)
#else
    #define MYLIB_API __declspec(dllimport)
#endif

MYLIB_API void SomeFunction();
MYLIB_API extern int SomeVariable;

请注意,__declspec(dllimport)__declspec(dllexport) 是 Microsoft Visual C++ 编译器的特定扩展,并且在其他编译器中可能有不同的实现方式。在其他平台或编译器中,你可能需要使用其他方法来处理导入和导出符号。

二、 __declspec(dllexport)和 extern "C" __declspec(dllexport)的区别

  1. 在C++编译器中使用__declspec(dllexport)导出的函数或者变量是按照C++的名称修饰规则导出的。C++ 默认使用名称修饰(name mangling)来支持函数重载和特殊类型等功能,这使得导出的函数无法被简单地从 DLL 中调用。
  2. extern "C" __declspec(dllexport):这个修饰符通常与 C++ 代码中的函数一起使用,并指示编译器使用 C 语言的命名和链接约定来导出函数。通过使用 extern "C",你告诉编译器使用 C 语言的命名约定导出函数,并使用 __declspec(dllexport) 将其添加到导出表中。

extern "C" 关键字对于纯粹的 C 代码来说通常是多余的,因为 C 本身默认使用 C 语言的命名和链接约定。

在跨语言的调用中一般都是按照C的方式来调用,C导出的函数名或者变量名不会被修饰,在python、C#中调用C/C++的函数或者变量都应该使用C的方式导出使用。

三、示例

要在 C++ 中将全局变量导出到 DLL 中,你需要使用适当的修饰符和导出声明。下面是一个示例,展示如何导出全局变量到 DLL 中:

  1. 在一个头文件中声明全局变量,并使用 __declspec(dllexport) 修饰符进行导出声明。例如,创建一个名为 "globals.h" 的头文件:
cpp 复制代码
// globals.h

#ifdef GLOBALS_EXPORTS
    #define GLOBALS_API __declspec(dllexport)
#else
    #define GLOBALS_API __declspec(dllimport)
#endif

GLOBALS_API extern int globalVar;

在上述代码中,我们使用 GLOBALS_API 宏来指定函数的导入和导出方式。

  1. 在一个源文件中定义全局变量。例如,创建一个名为 "globals.cpp" 的源文件:
cpp 复制代码
// globals.cpp

#include "globals.h"

GLOBALS_API int globalVar = 42;

在上述代码中,我们定义了一个全局变量 globalVar 并初始化为 42。

  1. 将 "globals.h" 和 "globals.cpp" 文件编译成 DLL。这可以通过编译器提供的相关选项或使用构建工具(如 Visual Studio)来完成。确保在生成 DLL 文件时定义 GLOBALS_EXPORTS 宏,以便在头文件中正确地设置 __declspec(dllexport)__declspec(dllimport)

  2. 在另一个项目中使用该 DLL。包含 "globals.h" 头文件,并使用 __declspec(dllimport) 修饰符进行导入声明。然后,可以像使用任何其他全局变量一样使用导入的全局变量:

cpp 复制代码
// main.cpp

#include "globals.h"
#include <iostream>

int main() {
    std::cout << "Global variable value: " << globalVar << std::endl;
    return 0;
}

请注意,导出的全局变量只能在 DLL 内部进行修改,而在主程序中只能进行读取。如果你需要在主程序中修改该全局变量的值并使其对 DLL 产生影响,你需要提供适当的函数接口来实现。(在实际使用时导出函数到DLL中不用把头文件中的__declspec(dllexport)改为__declspec(dllimport), 但是变量必须要,否则会报连接错误,找不到变量)。

相关推荐
唐诺4 小时前
几种广泛使用的 C++ 编译器
c++·编译器
冷眼看人间恩怨5 小时前
【Qt笔记】QDockWidget控件详解
c++·笔记·qt·qdockwidget
红龙创客5 小时前
某狐畅游24校招-C++开发岗笔试(单选题)
开发语言·c++
Lenyiin5 小时前
第146场双周赛:统计符合条件长度为3的子数组数目、统计异或值为给定值的路径数目、判断网格图能否被切割成块、唯一中间众数子序列 Ⅰ
c++·算法·leetcode·周赛·lenyiin
yuanbenshidiaos6 小时前
c++---------数据类型
java·jvm·c++
十年一梦实验室7 小时前
【C++】sophus : sim_details.hpp 实现了矩阵函数 W、其导数,以及其逆 (十七)
开发语言·c++·线性代数·矩阵
taoyong0017 小时前
代码随想录算法训练营第十一天-239.滑动窗口最大值
c++·算法
这是我587 小时前
C++打小怪游戏
c++·其他·游戏·visual studio·小怪·大型·怪物
fpcc7 小时前
跟我学c++中级篇——C++中的缓存利用
c++·缓存
呆萌很8 小时前
C++ 集合 list 使用
c++