C++导出函数

转自编程达人课件.


//方式1
//extern "C" _declspec(dllexport) 调用约定 返回类型 函数名(参数列表);
extern "C"
{
	_declspec(dllexport) int plus(int a,int b)
	{
		return a+b;
	}

	_declspec(dllexport) int sub(int a,int b)
	{
		return a-b;
	}


	_declspec(dllexport) int mul(int a,int b)
	{
		return a*b;
	}


	_declspec(dllexport) int div(int a,int b)
	{
		return a/b;
	}
}

//方式2
int plusNum(int a,int b)
{
	return a+b;
}


int subNum(int a,int b)
{
	return a-b;
}


int mulNum(int a,int b)
{
	return a*b;
}


int divNum(int a,int b)
{
	return a/b;
}
建立文本文件test.def
//函数名 @编号
//函数名 @编号 NONAME
文件内容如下:
EXPORTS

plusNum  @3
subNum  @5
mulNum  @6 NONAME
divNum  @7
------------------------------------------
调用方式:
方式1:
#include "stdafx.h"
#include<iostream>
#include<Windows.h>
#include<time.h>


using namespace std;
typedef int(*DllFun)(int,int);
//调用DLL案例
int main(int argc, char* argv[])
{
	DllFun plus;
	DllFun sub;
	DllFun mul;
	DllFun div;
	HINSTANCE hdll;
	//hdll=LoadLibrary("./DemoDll.dll");
	hdll=LoadLibrary("C:\\Program Files\\Microsoft Visual Studio\\MyProjects\\DemoDll\\Debug\\DemoDll.dll");
	if(hdll==NULL)
	{
		FreeLibrary(hdll);
		printf("load失败");
	}
	plus=(DllFun)GetProcAddress(hdll,"plus");
	sub=(DllFun)GetProcAddress(hdll,"sub");
	mul=(DllFun)GetProcAddress(hdll,"mul");
	div=(DllFun)GetProcAddress(hdll,"div");
	if(plus==NULL)
	{
		FreeLibrary(hdll);
	}
	cout<<plus(3,2)<<"\n";
	cout<<sub(3,2)<<"\n";
	cout<<mul(3,2)<<"\n";
	cout<<div(4,2)<<"\n";
	printf("Hello World!\n");
	return 0;
}


如何实现调用时DLL无需导出函数?

LoadLibrary加载dll,在DllMain里创建新线程调用自己的功能块儿(做好互斥等细节,防止重复调用)


2、创建动态链接库


<1>  extern "C" _declspec(dllexport) 调用约定 返回类型 函数名 (参数列表); 


<2>  使用.def文件:


EXPORTS
函数名 @编号
函数名 @编号 NONAME


使用序号导出的好处:

名字是一段程序就精华的注释,通过名字可以直接猜测到函数的功能
通过使用序号,可以达到隐藏的目的

3、使用动态链接库


步骤1: //定义函数指针,如:
typedef int (__stdcall *lpPlus)(int,int);
typedef int (__stdcall *lpSub)(int,int);
步骤2: //声明函数指针变量,如:
lpPlus myPlus;
lpSub mySub;
步骤3: //动态加载dll到内存中,如:
HINSTANCE   hModule = LoadLibrary("DllDemo.dll");
步骤4: //获取函数地址,如:
myPlus = (lpPlus)GetProcAddress(hModule,   "Plus");
mySub = (lpSub)GetProcAddress(hModule,   (char*)0x10);
步骤5: //调用函数,如:
int a = myPlus(10,2);
int b = mySub(10,2);
步骤6: //释放动态链接库,如:
FreeLibrary(hModule);

<think>好的,我现在需要回答用户的问题:“c++ 导出函数的默认约束是什么”。首先,我需要明确用户的问题到底在问什么。这里的“导出函数”可能指的是在C++中从一个模块(比如DLL或共享库)导出函数,或者是函数模板的导出?不过,在C++标准中,导出函数通常可能是指使用`export`关键字的函数模板,但C++11之后这个特性已经被移除了。不过,用户可能是在问关于动态链接库(DLL)中导出函数的默认约束,比如在Windows下使用__declspec(dllexport)或__stdcall等。 接下来,我需要确定用户的问题背景。如果用户是在开发跨平台的库,或者在使用DLL时遇到链接问题,可能需要了解导出函数的默认调用约定、名称修饰规则、以及如何显式导出函数。例如,在Windows平台上,如果不显式指定调用约定,函数的默认调用方式是什么?名称修饰(name mangling)如何影响导出函数名?此外,还需要考虑不同编译器之间的兼容性问题,比如MSVC和GCC在导出函数时的差异。 然后,我需要回忆C++导出函数的相关知识。在Windows上,导出函数通常使用__declspec(dllexport)来标记,而导入时使用__declspec(dllimport)。默认情况下,函数的调用约定可能是__cdecl,而名称修饰会根据调用约定和编译器的不同而变化。对于extern "C"的情况,可以禁用名称修饰,使得函数名以C风格导出,这样更易于在外部调用,比如从C代码或其他语言调用。 另外,如果用户指的是函数模板的导出,虽然export关键字已经被弃用,但可能需要提及这一点,但根据用户的问题,更可能是指动态库的导出。所以需要集中在DLL导出的约束上。 接下来,我需要组织回答的结构。首先解释导出函数的默认调用约定,然后讨论名称修饰的影响,接着是如何显式导出函数,以及跨平台的注意事项。最后提供示例代码,并说明相关问题。 同时,需要确保回答准确,避免错误信息。例如,在Windows上,默认的调用约定是否为__cdecl?是的,对于MSVC编译器,默认是__cdecl,而__stdcall常用于Windows API。名称修饰规则中,不同的调用约定会导致不同的修饰方式,比如前导下划线和参数顺序等。 此外,还需要提到如果不显式导出函数,可能会导致链接时无法找到符号的问题,特别是在不同的编译器或平台上。例如,在Linux下,使用-fvisibility=hidden编译选项可以控制符号的可见性,默认可能不会自动导出所有函数,需要显式标记。 最后,需要确保相关问题部分涵盖调用约定、名称修饰、跨平台导出方法、显式导出的必要性以及符号可见性等问题,以帮助用户深入理解。</think>在C++中,**导出函数的默认约束**主要涉及**调用约定**、**名称修饰规则**、**符号可见性**以及**平台差异**。以下是具体约束和注意事项: --- ### 1. **默认调用约定** - **Windows(MSVC编译器)**: - 默认调用约定为 `__cdecl`(函数参数从右向左压栈,调用者负责清理栈)。 - 若未显式指定调用约定,导出函数将使用 `__cdecl`。 - **Linux/macOS(GCC/Clang)**: - 默认使用 `cdecl` 调用约定(无需显式标记)。 示例: ```cpp // Windows下等价于:int __cdecl AddNumbers(int a, int b) int AddNumbers(int a, int b) { return a + b; } ``` --- ### 2. **名称修饰(Name Mangling)** - **C++编译器会通过名称修饰区分函数重载**,导致导出函数名与源码名称不同。 - **C语言兼容性**:使用 `extern "C"` 禁用名称修饰,确保导出函数名与源码一致。 示例: ```cpp // 导出未修饰名称(C风格) extern "C" { int AddNumbers(int a, int b) { return a + b; } // 导出名称为 "AddNumbers" } ``` --- ### 3. **符号可见性(Symbol Visibility)** - **Windows**:默认不导出任何函数,需显式使用 `__declspec(dllexport)` 标记导出函数。 - **Linux/macOS**:默认导出所有函数(除非使用 `-fvisibility=hidden` 隐藏符号)。 显式导出示例: ```cpp // Windows DLL导出 #ifdef _WIN32 #define API_EXPORT __declspec(dllexport) #else #define API_EXPORT #endif API_EXPORT int AddNumbers(int a, int b) { return a + b; } ``` --- ### 4. **跨平台导出约束** - **调用约定一致性**:若需跨平台调用,建议显式指定调用约定(如 `__stdcall`)。 - **符号可见性控制**:Linux/macOS 使用 `__attribute__((visibility("default")))` 显式导出函数。 跨平台示例: ```cpp // 显式导出(兼容Windows/Linux/macOS) #if defined(_WIN32) #define API_EXPORT __declspec(dllexport) #elif defined(__GNUC__) #define API_EXPORT __attribute__((visibility("default"))) #else #define API_EXPORT #endif API_EXPORT int AddNumbers(int a, int b) { return a + b; } ``` --- ### 5. **导出函数的限制** - **无法直接导出C++类成员函数**(需通过静态函数或封装为C接口)。 - **模板函数需显式实例化**才能导出。 - **异常处理**:导出函数不应抛出异常(跨平台兼容性问题)。 --- ### 示例:Windows DLL导出完整代码 ```cpp // dllmain.cpp #include <windows.h> BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { return TRUE; } // 导出函数 extern "C" __declspec(dllexport) int AddNumbers(int a, int b) { return a + b; } ``` --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值