XS PPCODE not behaving



我正在使用XS从我的Perl项目中调用第三方DLL,在Windows上的Cygwin下使用g++。其中一个DLL函数将结构作为参数,并在指向结构的指针中返回其主要结果。现在,我传入一个包含28个整数的平面列表,并填充第一个结构。然后我调用函数。然后,我想将得到的结构展平为一个最多包含54个整数的列表。

(这看起来像是很多整数,但DLL函数相当复杂,运行需要很长时间,所以我认为这是值得的。除非有人有更好的想法?(

这就快要奏效了。我可以看出,结果基本上是合理的。但有两个奇怪的问题。

  1. 当我打印出相同的变量时,我会得到不同的结果,这取决于它是否在"for"循环中!我在下面展示这个。我已经盯着这个看了这么久了。

  2. 当我到达第一个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之前,所有其他可能会解决这个问题。

相关内容

  • 没有找到相关文章

最新更新