再议:__cdecl与__stdcall 调用约定在动态链接库调用中不同的表现

2023-12-16 16:08

本文主要是介绍再议:__cdecl与__stdcall 调用约定在动态链接库调用中不同的表现,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

dll中函数声明

                  dll中函数名                   

 

void __declspec(dllexport) add(int, int)

?add@@YAXHH@Z

 

extern "C" void __declspec(dllexport) add(int, int)

add

 

void __declspec(dllexport) __stdcall add(int, int)

?add@@YGXHH@Z

 

extern "C" void __declspec(dllexport) __stdcall add(int, int)

_add@8

 

主调程序必需用相同的符号调用,但c++各个编译器生成符号不同,因此为了方便,也为了与c的混合编程,一般用c++编译器编写dll时,

声明为 extern "C" ,而主调程序也同时声明为extern "C" (或 不声明,只靠C++编译器生成一个混乱的名称,但这是就要求 dll 的编译器与主调程序的编译器相同,

则它们生成的混乱名称也相同)

 

即使是 extern "C" 碰到 stdcall 时,当采用GetProcAddress也找不到 add 这个函数,(因为名称已经变掉了,静态调用时,编译器也会按stdcall生成的函数名_add@8 在外部查找函数,所以不影响,但动态调用则不行),无语了,这时候要 def 文件 登场

 

当启用def文件后,不再需要__declspec(dllexport)申明相关函数为导出函数

LIBRARY "xxx"

EXPORTS
       add

 

dll中文件名都变成add,但不影响导入库lib文件,也就是静态调用动态链接库时,仍要确保 两边 编译器 生成的函数名一样,所以通常推荐两边同时声明 extern "C" ,不然很难确保不同的c++编译器生成相同的函数名,这里为了搞清问题,两边使用同一种编译器,考虑了四种情况。

 

例子:

在动态链接库 xxx.dll 代码中,(已启用def文件,所以省略__declspec(dllexport))

void add(int, int)
{
return ;
}

以c++方式导出函数,编译器处理为?add@@YAXHH@Z
主调程序中,GetProcAddress调用成功,静态调用时,函数申明分别为

函数申明错误 
extern "C" void add(int,int);无法解析的外部符号_add链接不通过
void add(int,int);/(同一个编译器给了个同一函数名来外部链接)        链接通过

 

在xxx.dll 代码中,

extern "C" void add(int, int)
{
return ;
}

以c方式导出函数,编译器处理为_add(为什么不是add?)
因为启用了def文件,所以主调程序的GetProcAddress无论如何都成功,而静态调用情况如下:

函数声明错误 
extern "C" void add(int,int);/同样生成_add外部链接成功链接通过
void add(int,int);"void __cdecl add(int,int)" (?add@@YAXHH@Z)       链接不通过

 

参考:

http://blog.csdn.net/wujian53/article/details/706975
http://hi.baidu.com/luosiyong/item/88a97b0e3bd0ee8802ce1b0b
http://blog.csdn.net/friday5pm/article/details/1532212

 

相关代码下载,dll 文件的位置需在运行时再调整,否则提示找不到xx.dll

http://download.csdn.net/detail/silyvin/5467251

 

这篇关于再议:__cdecl与__stdcall 调用约定在动态链接库调用中不同的表现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/501070

相关文章

在C#中调用Python代码的两种实现方式

《在C#中调用Python代码的两种实现方式》:本文主要介绍在C#中调用Python代码的两种实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录C#调用python代码的方式1. 使用 Python.NET2. 使用外部进程调用 Python 脚本总结C#调

MySQL中慢SQL优化的不同方式介绍

《MySQL中慢SQL优化的不同方式介绍》慢SQL的优化,主要从两个方面考虑,SQL语句本身的优化,以及数据库设计的优化,下面小编就来给大家介绍一下有哪些方式可以优化慢SQL吧... 目录避免不必要的列分页优化索引优化JOIN 的优化排序优化UNION 优化慢 SQL 的优化,主要从两个方面考虑,SQL 语

SpringCloud之LoadBalancer负载均衡服务调用过程

《SpringCloud之LoadBalancer负载均衡服务调用过程》:本文主要介绍SpringCloud之LoadBalancer负载均衡服务调用过程,具有很好的参考价值,希望对大家有所帮助,... 目录前言一、LoadBalancer是什么?二、使用步骤1、启动consul2、客户端加入依赖3、以服务

Vue 调用摄像头扫描条码功能实现代码

《Vue调用摄像头扫描条码功能实现代码》本文介绍了如何使用Vue.js和jsQR库来实现调用摄像头并扫描条码的功能,通过安装依赖、获取摄像头视频流、解析条码等步骤,实现了从开始扫描到停止扫描的完整流... 目录实现步骤:代码实现1. 安装依赖2. vue 页面代码功能说明注意事项以下是一个基于 Vue.js

讯飞webapi语音识别接口调用示例代码(python)

《讯飞webapi语音识别接口调用示例代码(python)》:本文主要介绍如何使用Python3调用讯飞WebAPI语音识别接口,重点解决了在处理语音识别结果时判断是否为最后一帧的问题,通过运行代... 目录前言一、环境二、引入库三、代码实例四、运行结果五、总结前言基于python3 讯飞webAPI语音

C#集成DeepSeek模型实现AI私有化的流程步骤(本地部署与API调用教程)

《C#集成DeepSeek模型实现AI私有化的流程步骤(本地部署与API调用教程)》本文主要介绍了C#集成DeepSeek模型实现AI私有化的方法,包括搭建基础环境,如安装Ollama和下载DeepS... 目录前言搭建基础环境1、安装 Ollama2、下载 DeepSeek R1 模型客户端 ChatBo

Java中将异步调用转为同步的五种实现方法

《Java中将异步调用转为同步的五种实现方法》本文介绍了将异步调用转为同步阻塞模式的五种方法:wait/notify、ReentrantLock+Condition、Future、CountDownL... 目录异步与同步的核心区别方法一:使用wait/notify + synchronized代码示例关键

Python调用Orator ORM进行数据库操作

《Python调用OratorORM进行数据库操作》OratorORM是一个功能丰富且灵活的PythonORM库,旨在简化数据库操作,它支持多种数据库并提供了简洁且直观的API,下面我们就... 目录Orator ORM 主要特点安装使用示例总结Orator ORM 是一个功能丰富且灵活的 python O

Java调用DeepSeek API的最佳实践及详细代码示例

《Java调用DeepSeekAPI的最佳实践及详细代码示例》:本文主要介绍如何使用Java调用DeepSeekAPI,包括获取API密钥、添加HTTP客户端依赖、创建HTTP请求、处理响应、... 目录1. 获取API密钥2. 添加HTTP客户端依赖3. 创建HTTP请求4. 处理响应5. 错误处理6.

Python如何计算两个不同类型列表的相似度

《Python如何计算两个不同类型列表的相似度》在编程中,经常需要比较两个列表的相似度,尤其是当这两个列表包含不同类型的元素时,下面小编就来讲讲如何使用Python计算两个不同类型列表的相似度吧... 目录摘要引言数字类型相似度欧几里得距离曼哈顿距离字符串类型相似度Levenshtein距离Jaccard相