21xrx.com
2025-03-31 00:26:46 Monday
文章检索 我的文章 写文章
C++调用C语言DLL出现异常问题
2023-07-08 19:35:47 深夜i     14     0
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的问题,确保程序的正常执行。

  
  

评论区

请求出错了