XS PPCODE 不工作

问题描述 投票:0回答:2

我正在使用 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);

这是输出。 返回码就OK了。 节点和卡则不然。 如果你眯着眼睛,你可能会注意到输出表中也出现了 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!
perl xs
2个回答
1
投票

确实是堆栈的问题。

提供的dll.h测试了

_WIN32
#define
'd
STDCALL
__stdcall
下的
_WIN32
,否则为空。

Cygwin 下的

g++ 不会发出

_WIN32
,所以我猜调用约定默认为
__cdecl

手动定义

_WIN32
会产生很多其他错误,但我在 dll.h 中添加了对
\__CYGWIN__
的测试,编译器确实会发出该测试,并将其提供给作者以用于他的下一个版本。

这是一个非常令人沮丧的错误,所以我希望这可以帮助将来的其他人。 你永远不知道...


0
投票

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

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

© www.soinside.com 2019 - 2024. All rights reserved.