我正在使用XS从我的Perl项目中调用第三方DLL,在Windows上的Cygwin下使用g++。其中一个DLL函数将结构作为参数,并在指向结构的指针中返回其主要结果。现在,我传入一个包含28个整数的平面列表,并填充第一个结构。然后我调用函数。然后,我想将得到的结构展平为一个最多包含54个整数的列表。
(这看起来像是很多整数,但DLL函数相当复杂,运行需要很长时间,所以我认为这是值得的。除非有人有更好的想法?(
这就快要奏效了。我可以看出,结果基本上是合理的。但有两个奇怪的问题。
-
当我打印出相同的变量时,我会得到不同的结果,这取决于它是否在"for"循环中!我在下面展示这个。我已经盯着这个看了这么久了。
-
当我到达第一个XPUSH时,我就会"失去记忆"。
这是XS代码。
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "ppport.h"
#include "dll.h"
MODULE = Bridge::Solver::DDS_IF PACKAGE = Bridge::Solver::DDS_IF
PROTOTYPES: ENABLE
void
SolveBoard(inlist)
SV * inlist
INIT:
struct deal dl;
struct futureTricks fut;
int target, solutions, mode, thrId;
int i, j, ret;
if ((! SvROK(inlist)) ||
(SvTYPE(SvRV(inlist)) != SVt_PVAV) ||
av_len((AV *) SvRV(inlist)) != 27)
{
XSRETURN_UNDEF;
}
printf("New INIT OKn");
PPCODE:
dl.trump = SvIV(*av_fetch((AV *)SvRV(inlist), 0, 0));
dl.first = SvIV(*av_fetch((AV *)SvRV(inlist), 1, 0));
dl.currentTrickSuit[0] = SvIV(*av_fetch((AV *)SvRV(inlist), 2, 0));
dl.currentTrickSuit[1] = SvIV(*av_fetch((AV *)SvRV(inlist), 3, 0));
dl.currentTrickSuit[2] = SvIV(*av_fetch((AV *)SvRV(inlist), 4, 0));
dl.currentTrickRank[0] = SvIV(*av_fetch((AV *)SvRV(inlist), 5, 0));
dl.currentTrickRank[1] = SvIV(*av_fetch((AV *)SvRV(inlist), 6, 0));
dl.currentTrickRank[2] = SvIV(*av_fetch((AV *)SvRV(inlist), 7, 0));
dl.remainCards[0][0] = SvUV(*av_fetch((AV *)SvRV(inlist), 8, 0));
dl.remainCards[0][1] = SvUV(*av_fetch((AV *)SvRV(inlist), 9, 0));
dl.remainCards[0][2] = SvUV(*av_fetch((AV *)SvRV(inlist), 10, 0));
dl.remainCards[0][3] = SvUV(*av_fetch((AV *)SvRV(inlist), 11, 0));
dl.remainCards[1][0] = SvUV(*av_fetch((AV *)SvRV(inlist), 12, 0));
dl.remainCards[1][1] = SvUV(*av_fetch((AV *)SvRV(inlist), 13, 0));
dl.remainCards[1][2] = SvUV(*av_fetch((AV *)SvRV(inlist), 14, 0));
dl.remainCards[1][3] = SvUV(*av_fetch((AV *)SvRV(inlist), 15, 0));
dl.remainCards[2][0] = SvUV(*av_fetch((AV *)SvRV(inlist), 16, 0));
dl.remainCards[2][1] = SvUV(*av_fetch((AV *)SvRV(inlist), 17, 0));
dl.remainCards[2][2] = SvUV(*av_fetch((AV *)SvRV(inlist), 18, 0));
dl.remainCards[2][3] = SvUV(*av_fetch((AV *)SvRV(inlist), 19, 0));
dl.remainCards[3][0] = SvUV(*av_fetch((AV *)SvRV(inlist), 20, 0));
dl.remainCards[3][1] = SvUV(*av_fetch((AV *)SvRV(inlist), 21, 0));
dl.remainCards[3][2] = SvUV(*av_fetch((AV *)SvRV(inlist), 22, 0));
dl.remainCards[3][3] = SvUV(*av_fetch((AV *)SvRV(inlist), 23, 0));
target = SvIV(*av_fetch((AV *)SvRV(inlist), 24, 0));
solutions = SvIV(*av_fetch((AV *)SvRV(inlist), 25, 0));
mode = SvIV(*av_fetch((AV *)SvRV(inlist), 26, 0));
thrId = SvIV(*av_fetch((AV *)SvRV(inlist), 27, 0));
ret = SolveBoard(dl, target, solutions, mode, &fut, thrId);
printf("Return code %dn", ret);
printf("Nodes %dn", fut.nodes);
printf("Cards %dn", fut.cards);
printf("%6s %12s %12s %12s %12sn",
"", "suit", "rank", "equals", "score");
printf("%6d %12d %12d %12d %12dnn",
0, fut.suit[0], fut.rank[0], fut.equals[0], fut.score[0]);
for (i = 0; i < 13; i++)
{
printf("%6d %12d %12d %12d %12dn",
i, fut.suit[i], fut.rank[i], fut.equals[i], fut.score[i]);
}
printf("n%6d %12d %12d %12d %12dnn",
0, fut.suit[0], fut.rank[0], fut.equals[0], fut.score[0]);
printf("Trying to push nodesn");
XPUSHs(sv_2mortal(newSViv(fut.nodes)));
printf("Trying to push cardsn");
XPUSHs(sv_2mortal(newSViv(fut.cards)));
printf("Trying to loopn");
for (i = 0; i <= 12; i++)
{
XPUSHs(sv_2mortal(newSViv(fut.suit [i])));
XPUSHs(sv_2mortal(newSViv(fut.rank [i])));
XPUSHs(sv_2mortal(newSViv(fut.equals[i])));
XPUSHs(sv_2mortal(newSViv(fut.score [i])));
}
printf("Done loopingn");
这是DLL头文件的相关部分。
struct futureTricks
{
int nodes;
int cards;
int suit[13];
int rank[13];
int equals[13];
int score[13];
};
struct deal
{
int trump;
int first;
int currentTrickSuit[3];
int currentTrickRank[3];
unsigned int remainCards[4][4];
};
extern "C" int SolveBoard(
struct deal dl,
int target,
int solutions,
int mode,
struct futureTricks *futp,
int threadIndex);
这是输出。返回代码正常。节点和卡不正常。如果你斜视,你可能会注意到0和768也出现在输出表中,所以可能有某种偏移
第一件奇怪的事情是,主表前后的两行"0"与主表中的"0"不同。不过,主表中的数据与预期的一样,包括第10-12行中的垃圾。
第二个问题是XPUSH没有按预期工作。
New INIT OK
Return code 1
Nodes 0
Cards 768
suit rank equals score
0 0 2 -2147319000 -2147296756
0 2 2 0 2
1 2 6 0 2
2 2 10 768 2
3 2 13 0 2
4 3 14 0 2
5 0 6 0 1
6 0 10 512 1
7 0 13 0 1
8 3 4 0 0
9 3 11 0 0
10 1773292640 -2147056120 4 -2147319000
11 1772354411 0 -2146989552 -2146837752
12 8192 35 2665016 -2147319000
0 0 2 -2147319000 -2147296756
Trying to push nodes
Out of memory!
这确实是堆栈的问题。
提供的dll.h在_WIN32
下测试了_WIN32
和#define
'd STDCALL
到__stdcall
,否则为空。
Cygwin下的g++不发出_WIN32
,所以我猜调用约定默认为__cdecl
。
手动定义_WIN32
会产生很多其他错误,但我在dll.h中添加了一个__CYGWIN__
的测试,编译器确实会发出这个测试,并将其交给作者进行下一次发布。
这是一个非常令人沮丧的错误,所以我希望这可能会在未来帮助其他人。你永远不会知道。。。
对于偏移量问题,可能是因为Perl在C变量定义方面做得很糟糕。
包括dll.h之前,所有其他可能会解决这个问题。