0

我正在使用 XS 在 Windows 上的 Cygwin 下使用 g++ 从我的 Perl 项目中调用第三方 DLL。其中一个 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 OK\n");
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 %d\n", ret);
  printf("Nodes %d\n", fut.nodes);
  printf("Cards %d\n", fut.cards);

  printf("%6s  %12s  %12s  %12s  %12s\n",
    "", "suit", "rank", "equals", "score");
  printf("%6d  %12d  %12d  %12d  %12d\n\n",
    0, fut.suit[0], fut.rank[0], fut.equals[0], fut.score[0]);

  for (i = 0; i < 13; i++)
  {
    printf("%6d  %12d  %12d  %12d  %12d\n",
      i, fut.suit[i], fut.rank[i], fut.equals[i], fut.score[i]);
  }

  printf("\n%6d  %12d  %12d  %12d  %12d\n\n",
    0, fut.suit[0], fut.rank[0], fut.equals[0], fut.score[0]);

  printf("Trying to push nodes\n");
  XPUSHs(sv_2mortal(newSViv(fut.nodes)));

  printf("Trying to push cards\n");
  XPUSHs(sv_2mortal(newSViv(fut.cards)));

  printf("Trying to loop\n");
  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 looping\n");

这是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!
4

2 回答 2

1

这确实是堆栈的问题。

提供的 dll.h 测试_WIN32#define'dSTDCALL__stdcallunder _WIN32,否则清空。

Cygwin 下的 g++ 不会发出_WIN32,所以我猜调用约定默认为__cdecl.

手动定义_WIN32会产生许多其他错误,但我将其添加到\__CYGWIN__编译器确实发出的 dll.ha test for 中,并将其提供给作者以供下一个版本使用。

发现一个非常令人沮丧的错误,所以我希望这可能对其他人有所帮助。你永远不会知道...

于 2014-06-03T08:04:58.873 回答
0

对于偏移量问题,可能是因为 Perl 对 C 变量定义的处理非常糟糕。

在所有其他人之前包括 dll.h 可能会解决这个问题。

于 2014-06-02T08:26:29.223 回答