21xrx.com
2024-06-03 01:19:23 Monday
登录
文章检索 我的文章 写文章
C++调用C语言DLL出现异常问题
2023-07-08 19:35:47 深夜i     --     --
C++ C语言DLL 异常问题

在软件开发过程中,我们经常会使用到DLL(动态链接库)来实现模块化的设计,并且提高程序的运行效率。然而,在C++调用C语言DLL的过程中,有时会出现异常的问题。本文将重点讨论这个问题以及解决方法。

一、问题描述

当我们在C++中调用C语言的DLL时,有时候会出现异常,如下面的代码:


#include <iostream>

#include <Windows.h>

using namespace std;

int main() {

  HINSTANCE hDll = LoadLibraryA("test.dll");

  if (NULL == hDll)

    cout << "unable to load DLL file" << endl;

    return -1;

  

  int (*add)(int, int);

  add = (int (*)(int, int))GetProcAddress(hDll, "Add");

  if (NULL == add) {

    cout << "unable to find exported function" << endl;

    FreeLibrary(hDll);

    return -1;

  }

  int result = add(1,2);

  cout << result << endl;

  FreeLibrary(hDll);

  return 0;

}

这段代码是一个简单的C++调用C语言DLL的示例代码。假设test.dll中有导出函数Add可以实现两数相加的功能,我们在C++中通过LoadLibraryA函数加载该DLL,并通过GetProcAddress函数获取Add函数的入口地址,最后通过add(1,2)调用Add函数实现计算。

当我们运行上述代码时,有些时候会出现异常的情况,如下图所示:

![C++调用C语言DLL出现异常](https://img-blog.csdn.net/20160418161006587)

我们可以看到,程序提示“未经处理的异常”,并且显示的错误信息是“Access violation reading location 0x00000000”。这是什么原因导致的呢?我们需要通过调试来查明。

二、问题分析

我们重新运行上述代码,并在Visual Studio 2015中打开调试器,单步执行代码。当执行到add(1,2)时,程序提示该代码处于“未知的源文件”中,我们需要进入测试.dll的源文件查看代码。

我们可以看到,test.dll的源代码如下:


#include <stdio.h>

#include <stdlib.h>

#include "test.h"

#if defined _WIN32 || defined _WIN64

#define EXPORT_FUNCTION __declspec(dllexport)

#elif defined __linux__

#define EXPORT_FUNCTION __attribute__((visibility("default")))

#else

#error Unknown system

#endif

EXPORT_FUNCTION int Add(int x, int y) {

  return x + y;

}

这是一个简单的C语言代码,实现了Add函数,我们可以看到,Add函数是一个导出函数,通过__declspec(dllexport)实现在DLL中导出。

我们返回到C++示例代码中,发现问题出在以下代码:


int (*add)(int, int);

add = (int (*)(int, int))GetProcAddress(hDll, "Add");

我们通过GetProcAddress函数获取了Add函数的入口地址,并赋值给了add指针。然而,在执行add(1,2)时,程序出现了异常。通过调试,我们可以发现,add指针的值为NULL,也就是获取入口地址失败。

这是什么原因导致的呢?通过我们的分析,我们可以发现问题的关键在于导出函数符号的命名,也就是test.dll中导出函数Add的名字。

我们在测试.dll的头文件test.h中定义了Add函数的原型:


int Add(int x, int y);

这是一个C语言的函数声明,我们在测试.dll中实现了该函数,并通过__declspec(dllexport)导出。因此,Add函数的导出名字其实是带有一个下划线_的,也就是_export函数,而不是Add。

当我们修改C++示例代码中以下代码:


add = (int (*)(int, int))GetProcAddress(hDll, "Add");

为以下代码:


add = (int (*)(int, int))GetProcAddress(hDll, "_Add");

重新运行C++示例代码,可以发现程序运行正常,可以正确输出3。

三、解决方案

通过我们的分析,可以发现C++调用C语言DLL出现异常的问题其实是因为导出函数名字没有正确对应,因此C++无法获取到函数的入口地址,导致程序无法正常执行。

为了避免这种问题的发生,我们需要严格按照导出函数名称进行对应。C++调用C语言DLL时,需要在函数名前添加下划线_。例如,我们在C语言中定义了一个函数:


int Add(int x, int y);

我们可以在C++中通过以下方式进行调用:


add = (int (*)(int, int))GetProcAddress(hDll, "_Add");

通过遵循这一规则,可以避免C++调用C语言DLL的问题,确保程序的正常执行。

  
  

评论区

{{item['qq_nickname']}}
()
回复
回复