1

我编写了一个使用函数指针数组的 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 类型转换中完全指定类型(而不仅仅是 VECT *)。

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

有任何想法吗?

4

2 回答 2

2

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

VECT (*normal)();

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

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

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

于 2013-06-14T16:10:53.240 回答
0

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

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

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

于 2013-06-14T15:02:57.973 回答