再议:__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

相关文章

2. c#从不同cs的文件调用函数

1.文件目录如下: 2. Program.cs文件的主函数如下 using System;using System.Collections.Generic;using System.Linq;using System.Threading.Tasks;using System.Windows.Forms;namespace datasAnalysis{internal static

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi

如何在页面调用utility bar并传递参数至lwc组件

1.在app的utility item中添加lwc组件: 2.调用utility bar api的方式有两种: 方法一,通过lwc调用: import {LightningElement,api ,wire } from 'lwc';import { publish, MessageContext } from 'lightning/messageService';import Ca

uva 10061 How many zero's and how many digits ?(不同进制阶乘末尾几个0)+poj 1401

题意是求在base进制下的 n!的结果有几位数,末尾有几个0。 想起刚开始的时候做的一道10进制下的n阶乘末尾有几个零,以及之前有做过的一道n阶乘的位数。 当时都是在10进制下的。 10进制下的做法是: 1. n阶位数:直接 lg(n!)就是得数的位数。 2. n阶末尾0的个数:由于2 * 5 将会在得数中以0的形式存在,所以计算2或者计算5,由于因子中出现5必然出现2,所以直接一

速了解MySQL 数据库不同存储引擎

快速了解MySQL 数据库不同存储引擎 MySQL 提供了多种存储引擎,每种存储引擎都有其特定的特性和适用场景。了解这些存储引擎的特性,有助于在设计数据库时做出合理的选择。以下是 MySQL 中几种常用存储引擎的详细介绍。 1. InnoDB 特点: 事务支持:InnoDB 是一个支持 ACID(原子性、一致性、隔离性、持久性)事务的存储引擎。行级锁:使用行级锁来提高并发性,减少锁竞争

【LabVIEW学习篇 - 21】:DLL与API的调用

文章目录 DLL与API调用DLLAPIDLL的调用 DLL与API调用 LabVIEW虽然已经足够强大,但不同的语言在不同领域都有着自己的优势,为了强强联合,LabVIEW提供了强大的外部程序接口能力,包括DLL、CIN(C语言接口)、ActiveX、.NET、MATLAB等等。通过DLL可以使用户很方便地调用C、C++、C#、VB等编程语言写的程序以及windows自带的大

MyBatis 切换不同的类型数据库方案

下属案例例当前结合SpringBoot 配置进行讲解。 背景: 实现一个工程里面在部署阶段支持切换不同类型数据库支持。 方案一 数据源配置 关键代码(是什么数据库,该怎么配就怎么配) spring:datasource:name: test# 使用druid数据源type: com.alibaba.druid.pool.DruidDataSource# @需要修改 数据库连接及驱动u

linux中使用rust语言在不同进程之间通信

第一种:使用mmap映射相同文件 fn main() {let pid = std::process::id();println!(

string字符会调用new分配堆内存吗

gcc的string默认大小是32个字节,字符串小于等于15直接保存在栈上,超过之后才会使用new分配。

京东物流查询|开发者调用API接口实现

快递聚合查询的优势 1、高效整合多种快递信息。2、实时动态更新。3、自动化管理流程。 聚合国内外1500家快递公司的物流信息查询服务,使用API接口查询京东物流的便捷步骤,首先选择专业的数据平台的快递API接口:物流快递查询API接口-单号查询API - 探数数据 以下示例是参考的示例代码: import requestsurl = "http://api.tanshuapi.com/a