3

我是 XS 的初学者,花了一些时间在网上寻找这个答案,但没有运气。问题是 XS 改变了函数的名称,当它编译时,我会得到一个未定义的引用错误。例如考虑下面的 XS 代码:

size_t 
matrixIndex (colIndex, rowIndex,nCols,nRows)
      size_t colIndex
      size_t rowIndex
      size_t nCols
      size_t nRows
    CODE:
    size_t register i;
    RETVAL = (rowIndex * nCols) + colIndex;
    OUTPUT:
        RETVAL

然后我尝试在下面的函数中使用它

int
matrixCopyColumnVector_dbl (colIndex,fromMatrix,nColsMatrix,nRowsMatrix,intoVector,nRowsVector)
      size_t colIndex
      SV * fromMatrix
      size_t nColsMatrix
      size_t nRowsMatrix
      SV * intoVector
      size_t nRowsVector
    CODE:
      size_t register x, n;
      if( nRowsVector != nRowsMatrix) { RETVAL = 0; return RETVAL; }
      n = 0;
      for(x=0; x<= nRowsMatrix; x++) {
         intoVector[n] = fromMatrix[matrixIndex /*USE OF FUNCTION HERE!!*/(colIndex,x,nColsMatrix,nRowsMatrix)];
         n++;
      }
      RETVAL = 1;
      return RETVAL;
    OUTPUT:
       RETVAL

然后我运行make它并通过编译过程,我在似乎是链接阶段的undefined reference to 'matrixIndex'.

所以我想知道从同一个 XS 文件中调用函数的标准 XS 方法是什么?

4

2 回答 2

5

XS 代码创建Perl子程序。所以调用 XS 函数与调用任何其他 Perl 子函数是一样的。

与其处理这种复杂性和低效率,不如创建一个 C 函数而不是 Perl 子程序。(如果您愿意,可以使用 XS 独立公开该 C 函数。)

#define PERL_NO_GET_CONTEXT
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"

static UV matrixIndex(UV colIndex, UV rowIndex, UV nCols, UV nRows) {
    return (rowIndex * nCols) + colIndex;
}

MODULE = Foo::Bar  PACKAGE = Foo::Bar

int
matrixCopyColumnVector_dbl(colIndex, fromMatrix, nColsMatrix, nRowsMatrix, intoVector, nRowsVector)
    UV colIndex
    SV * fromMatrix
    UV nColsMatrix
    UV nRowsMatrix
    SV * intoVector
    UV nRowsVector
PREINIT:
    UV register x, n;
CODE:
    if (nRowsVector == nRowsMatrix) {
        RETVAL = 0;
    } else {
        n = 0;
        for (x=0; x<=nRowsMatrix; x++) {
            intoVector[n] = fromMatrix[matrixIndex(colIndex, x, nColsMatrix, nRowsMatrix)];
            n++;
        }
        RETVAL = 1;
    }
OUTPUT:
    RETVAL

您的使用return不正确。如果您想提前返回,请使用其中一个XSRETURN*宏。

fromMatrix[...]并且intoVector[...]是完全错误的。fromMatrix并且intoVector是 C 数组。(它们甚至不是 Perl 数组,这无关紧要。)

Perl 整数的大小IV(或UV无符号),不一定size_t。使用那些以获得最佳兼容性。

如果你想要可移植性,你不能假设 C99,所以你不能混合声明和代码。您需要将声明放入PREINIT(或使用 curliesCODE为变量声明创建新范围)。

于 2017-10-04T16:21:20.820 回答
2

XSUB 不是 C 函数。XS 预处理器确实根据您的声明创建了一个 C 函数,但它具有签名void (CV*). 然后 XSUB 从 Perl 参数堆栈中获取参数并使用您的类型映射将它们转换为 C 值。因此无法直接调用您的 XSUB。

相反,您必须像调用任何其他 Perl 函数一样调用 XSUB,即将参数作为SV*s 压入堆栈。详情请参阅perldoc perlcall。显然,这是乏味且低效的。

一个更好的解决方案是在 XS 文件中将您想要从 Perl 和 XS 中使用的所有函数声明为staticC 函数,然后编写 XS 粘合代码以将其公开给 Perl。这里:

static size_t matrixIndex(size_t colIndex, size_t rowIndex, size_t nCols, size_t nRows)
{
    size_t register i;  // unneeded
    return (rowIndex * nCols) + colIndex;
}

请注意,如果此函数使用 Perl API 的任何部分,那么您还应该使用pTHXaTHX宏。声明更改为

static size_t matrixIndex(pTHX_ size_t colIndex, etc...) ...

当从 C 调用它时,你会写matrixIndex(aTHX_ colIndex, etc...).

于 2017-10-04T16:29:43.917 回答