Windows C++中__declspec(dllexport)的使用

__declspec是Microsoft VC中专用的关键字,它配合着一些属性可以对标准C/C++进行扩充。__declspec关键字应该出现在声明的前面。

__declspec(dllexport)用于Windows中的动态库中,声明导出函数、类、对象等供外面调用,省略给出.def文件。即将函数、类等声明为导出函数,供其它程序调用,作为动态库的对外接口函数、类等。

.def文件(模块定义文件)是包含一个或多个描述各种DLL属性的Module语句的文本文件。.def文件或__declspec(dllexport)都是将公共符号导入到应用程序或从DLL导出函数。如果不提供__declspec(dllexport)导出DLL函数,则DLL需要提供.def文件。

__declspec(dllimport)用于Windows中,从别的动态库中声明导入函数、类、对象等供本动态库或exe文件使用。当你需要使用DLL中的函数时,往往不需要显示地导入函数,编译器可自动完成。不使用__declspec(dllimport)也能正确编译代码,但使用__declspec(dllimport)使编译器可以生成更好的代码。编译器之所以能够生成更好的代码,是因为它可以确定函数是否存在于DLL中,这使得编译器可以生成跳过间接寻址级别的代码,而这些代码通常会出现在跨DLL边界的函数调用中。声明一个导入函数,是说这个函数是从别的DLL导入。一般用于使用某个DLL的exe中。

In Microsoft,the extended attribute syntax for specifying storage-class information uses the__declspec keyword, which specifies that an instance of a given type is to be stored with a Microsoft-specific storage-class attribute.

Extended attribute grammar supports these Microsoft-specific storage-class attributes:align, allocate, appdomain, code_seg, deprecated, dllexport, dllimport, jitintrinsic, naked, noalias, noinline, noreturn, nothrow, novtable, process,restrict, safebuffers, selectany, and thread. It also supports these COM-object attributes: property and uuid. The code_seg, dllexport, dllimport, naked,noalias, nothrow, property, restrict, selectany, thread, and uuid storage-class attributes are properties only of the declaration of the object or function to which they are applied. The thread attribute affects data and objects only. The naked attribute affects functions only. The dllimport and dllexport attributes affect functions, data, and objects. The property, selectany, and uuid attributes affect COM objects.

The __declspec keywords should be placed at the beginning of a simple declaration. The compiler ignores, without warning, any __declspec keywords placed after * or& and in front of the variable identifier in a declaration. A __declspec attribute specified in the beginning of a user-defined type declaration applies to the variable of that type.

The dllexport and dllimport storage-class attributes are Microsoft-specific extensions to the C and C++ languages. You can use them to export and import functions, data, and objects to or from a DLL. These attributes explicitly define the DLL's interface to its client, which can be the executable file or another DLL. Declaring functions as dllexport eliminates the need for a module-definition(.def) file, at least with respect to the specification of exported functions.The dllexport attribute replaces the __export keyword. If a class is marked declspec(dllexport), any specializations of class templates in the class hierarchy are implicitly marked as declspec(dllexport). This means that class templates are explicitly instantiated and the class's members must be defined.

dllexport of a function exposes the function with its decorated name. For C++ functions,this includes name mangling. For C functions or functions that are declared as extern "C", this includes platform-specific decoration that's based on the calling convention. To export an undecorated name, you can link by using a Module Definition (.def) file that defines the undecorated name in an EXPORTS section.

以下是测试代码:新建一个动态库工程Library,然后在CppBaseTest工程中调用Library的接口:

library.hpp:

#ifndef FBC_LIBRARY_LIBRARY_HPP_
#define FBC_LIBRARY_LIBRARY_HPP_

// reference: http://geoffair.net/ms/declspec.htm

#ifdef _MSC_VER
	#ifdef FBC_STATIC
		#define FBC_API
	#elif defined FBC_EXPORT
		#define FBC_API __declspec(dllexport)
	#else
		#define FBC_API __declspec(dllimport)
	#endif
#endif

#ifdef __cplusplus
extern "C" {
#endif

FBC_API int library_add(int a, int b);
FBC_API int value;

#ifdef __cplusplus
}
#endif

template<typename T>
class FBC_API Simple {
public:
	Simple() = default;
	void Init(T a, T b);
	T Add() const;

private:
	T a, b;
};


#endif // FBC_LIBRARY_LIBRARY_HPP_

library.cpp:

#include "library.hpp"
#include <iostream>
#include <string>

FBC_API int library_add(int a, int b)
{
	value = 11;

	fprintf(stdout, "File: %s, Function: %s, Line: %d\n", __FILE__, __FUNCTION__, __LINE__);
	return (a+b);
}

template<typename T>
void Simple<T>::Init(T a, T b)
{
	this->a = a;
	this->b = b;
}

template<typename T>
T Simple<T>::Add() const
{
	fprintf(stdout, "File: %s, Function: %s, Line: %d\n", __FILE__, __FUNCTION__, __LINE__);
	return (a + b);
}

template class Simple<int>;
template class Simple<std::string>;

test_library.hpp:

#ifndef FBC_CPPBASE_TEST_TEST_LIBRARY_HPP_
#define FBC_CPPBASE_TEST_TEST_LIBRARY_HPP_

#include <library.hpp>

namespace test_library_ {

#ifdef __cplusplus
	extern "C" {
#endif

__declspec(dllimport) int library_add(int, int);
__declspec(dllimport) int value;

#ifdef __cplusplus
	}
#endif

int test_library_1();
int test_library_2();

} // namespace test_library_

#endif // FBC_CPPBASE_TEST_TEST_LIBRARY_HPP_

test_library.cpp:

#include "test_library.hpp"
#include <iostream>
#include <string>

#include <library.hpp>

namespace test_library_ {

int test_library_1()
{
	int a{ 4 }, b{ 5 }, c{ 0 };

	c = library_add(a, b);
	fprintf(stdout, "%d + %d = %d\n", a, b, c);
	fprintf(stdout, "value: %d\n", value);

	return 0;
}

int test_library_2()
{
	Simple<int> simple1;
	int a{ 4 }, b{ 5 }, c{ 0 };

	simple1.Init(a, b);
	c = simple1.Add();
	fprintf(stdout, "%d + %d = %d\n", a, b, c);

	Simple<std::string> simple2;
	std::string str1{ "csdn blog: " }, str2{ "http://blog.csdn.net/fengbingchun" }, str3;

	simple2.Init(str1, str2);
	str3 = simple2.Add();
	fprintf(stdout, "contents: %s\n", str3.c_str());

	return 0;
}

} // namespace test_library_

GitHub: https://github.com/fengbingchun/Messy_Test  

 

  • 33
    点赞
  • 169
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
好的,以下是一个使用__declspec(dllexport)导出函数的例子: 首先,我们需要创建一个C++源文件,例如test.cpp,包含以下函数的实现: ```c++ #include <iostream> extern "C" __declspec(dllexport) int add(int a, int b) { return a + b; } extern "C" __declspec(dllexport) void print_name() { std::cout << "My name is ChitGPT!" << std::endl; } ``` 这里使用了extern "C"修饰函数,以确保函数以C语言的命名约定导出。然后,使用__declspec(dllexport)修饰函数,以将其导出为DLL的导出项。 然后,我们可以使用编译器将其编译为动态链接库,例如在Windows使用Visual Studio编译器,我们可以使用以下命令: ``` cl /LD test.cpp ``` 这将生成一个名为test.dll的动态链接库文件。 最后,我们可以在另一个C++程序使用test.dll的函数,例如: ```c++ #include <iostream> #include <Windows.h> typedef int (*AddFunc)(int, int); typedef void (*PrintNameFunc)(); int main() { HMODULE testDll = LoadLibrary("test.dll"); if (testDll == NULL) { std::cout << "Failed to load test.dll" << std::endl; return 1; } AddFunc add = (AddFunc)GetProcAddress(testDll, "add"); if (add == NULL) { std::cout << "Failed to get address of add function" << std::endl; return 1; } std::cout << "1 + 2 = " << add(1, 2) << std::endl; PrintNameFunc printName = (PrintNameFunc)GetProcAddress(testDll, "print_name"); if (printName == NULL) { std::cout << "Failed to get address of print_name function" << std::endl; return 1; } printName(); FreeLibrary(testDll); return 0; } ``` 这个程序首先使用LoadLibrary函数加载test.dll动态链接库,然后使用GetProcAddress函数获取test.dll的add和print_name函数的地址,并调用它们。最后,使用FreeLibrary函数卸载动态链接库。 这就是一个使用__declspec(dllexport)导出函数的例子。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值