【问题标题】:When calling a C++ DLL from a C program it crashes when I try to access call parameter pointer in the DLL从 C 程序调用 C++ DLL 时,当我尝试访问 DLL 中的调用参数指针时,它会崩溃
【发布时间】:2013-06-14 14:46:40
【问题描述】:

我编写了一个使用函数指针数组的 C 程序。这 函数既在我的程序内部,也在可加载的 DLL 中。我的问题来了 当我尝试使用来自 C++ 程序的 DLL 时。这里有一个简化的 C++ (DLL) 程序中的代码片段:

#ifdef __cplusplus
#define EXPORT extern "C" __declspec(dllexport)
#else
#define EXPORT __declspec(dllexport)
#endif

typedef struct { float x,y,z; } VECT;

EXPORT VECT norm(OBJECT *obj, RAY ray, float t, VECT *pt, RGB *col)
{
VECT npt;
...
*pt = npt;  /* give pt a new value */
...
}

问题是当我尝试对 pt 做任何事情时它就会崩溃。它不是 NULL,但如果我尝试写入它甚至只是访问它的成员,它 崩溃。我已经通过将 C++ 代码转换为 C 来解决这个问题,但是 我真的很想知道为什么会崩溃。如果我尝试 访问 pt,程序运行良好(除了缺少 会带有正确的pt)。顺便说一句,这是另一个奇怪的事情 - 当我在现在的 C DLL 代码中执行以下操作时:

EXPORT VECT norm(OBJECT *obj, RAY ray, float t, VECT *pt, RGB *col)

它崩溃了。但如果我这样做:

EXPORT VECT norm(obj, ray, t, pt, col)
OBJECT *obj;
VECT *pt;
RAY ray;
float t;
RGB *col;

它不会崩溃。有没有办法让 C++ 接受第二种方式 指定参数?

额外信息,以备不时之需...我加载 DLL 函数:

typedef struct Funcs
{
int (*inter)();
VECT (*normal)();
} FUNCS;

/*
 I've also tried:
typedef VECT (WINAPI *FNORMAL)(OBJECT *obj, RAY ray, float t, VECT *pt, RGB *col);
(FNORMAL)GetProcAddress...
*/

funcs[i].normal = (VECT *)GetProcAddress(dll2, "norm");
if (funcs[i].normal == NULL) { printf("Error: No norm procedure in '%s'\n", objstr); quit(); }

并通过以下方式调用他们:

hit.normal = funcs[p->type].normal(p, ray, mint, &pt, &colm);

我已经尝试在 GetProcAddress 类型转换。

我什至尝试在我的 linux 版本中执行此操作。它也崩溃了,所以它不是 仅 Windows 的问题。

有什么想法吗?

【问题讨论】:

  • 当它崩溃时,pt 的值在调用者的堆栈帧中与在 DLL/共享库中的值是否相同?
  • 什么是normal。请出示声明。实际上向我们展示了您传递的参数的声明。此外,GetProcAddress 的演员阵容看起来很假。
  • 有没有办法让 C++ 接受第二种指定参数的方式? 不,没有,你提出这个问题的事实是一个令人担忧的迹象。这类问题很容易解决。但是不要像无头鸡一样到处乱跑,随意尝试并选择不会崩溃的第一件事。了解问题。然后解决它。正确。
  • @Useless (指针的)值不一样。我现在在linux上,所以我不得不尝试使用linux版本。
  • @DavidHeffernan 我不确定您指的是哪个“正常”,但这是其中之一: typedef struct Funcs { int (*inter)(); VECT (*正常)(); } 功能;

标签: c++ c dll parameters crash


【解决方案1】:

对我来说,问题似乎源于此声明:

VECT (*normal)();

在这里你告诉编译器normal 是一个指向返回VECT 的函数的指针。但是你没有指定函数的参数,所以编译器会让你传递你喜欢的任何东西,它会尝试计算出要传递的类型。这是非常糟糕的做法。你应该停止这样做。将 normal 的声明改为如下:

VECT (*normal)(OBJECT *obj, RAY ray, float t, VECT *pt, RGB *col);

我在 C++ 代码中看不到任何指定调用约定的地方,因此假设cdecl 的默认值有效。显然,您需要在接口一侧匹配它,如果您没有为函数指针指定调用约定,那么您还将获得默认的 cdecl

【讨论】:

    【解决方案2】:

    您必须确保所有涉及的编译参数在 DLL 构建和客户端构建期间兼容。需要特别注意:

    • 函数调用约定
    • 结构填料
    • 结构内容

    如果所有这些看起来都不错,请在调用函数的地方中断,并显示作为参数传递的所有内容。然后进入函数并检查一切看起来是否相同。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-28
      • 1970-01-01
      • 1970-01-01
      • 2016-08-03
      相关资源
      最近更新 更多