【问题标题】:Moving binary data to/from Perl using SWIG使用 SWIG 将二进制数据移入/移出 Perl
【发布时间】:2011-07-12 05:00:08
【问题描述】:

我正在努力让我可以轻松地在 Perl 和我的 C++ 库之间移动二进制数据。

我创建了一个 c++ 结构来处理 binary_data:

struct binary_data {
    unsigned long length;
    unsigned char *data;
};

在我的 SWIG 接口文件中,我有以下内容:

%typemap(in) binary_data * (binary_data temp) {
    STRLEN len;
    unsigned char *outPtr;
    if(!SvPOK($input))
        croak("argument must be a scalar string");
    outPtr = (unsigned char*) SvPV($input, len);
        printf("set binary_data '%s' [%d] (0x%X)\n", outPtr, len, $input);
    temp.data = outPtr;
    temp.length = len;
    $1 = &temp;
}
%typemap(out) binary_data * {
  SV *obj = sv_newmortal();
  if ($1 != 0 && $1->data != 0 && $1->length > 0) {     
    sv_setpvn(obj, (const char*) $1->data, $1->length);
    printf("get binary_data '%s' [%d] (0x%X)\n", $1->data, $1->length, obj);
  } else {
    sv_setsv(obj, &PL_sv_undef);
    printf("get binary_data [set to undef]\n");
  }
  if( !SvPOK(obj) )
    croak("The result is not a scalar string"); 
  $result = obj;
}

我通过“ExtUtils::MakeMaker”构建了我的 Perl 模块,一切都很好。

然后我运行以下 perl 测试脚本以确保二进制数据正在 正确设置/获取 perl 字符串。

my $fr = ObjectThatContainsBinaryData->new();
my $data = "1234567890"; 
print ">>>PERL:swig_data_set\n"; 
$fr->swig_data_set($data);
print "<<<PERL:swig_data_set\n";
print ">>>PERL:swig_data_get\n"; 
my $rdata = $fr->swig_data_get();
print "<<<PERL: swig_data_get\n";
print "sent    :" . \$data . " len=" . length($data). " '$data'\n"
     ."recieved:". \$rdata.  " len=" . length($rdata). " '$rdata'\n";

现在组合的 C++ 和 Perl printf 标准输出是:

>>>PERL:swig_data_set
set binary_data '1234567890' [10] (0x12B204D0)
<<<PERL:swig_data_set
>>>PERL:swig_data_get
get binary_data '1234567890' [10] (0x1298E4E0)
<<<PERL: swig_data_get
sent    :SCALAR(0x12b204d0) len=10 '1234567890'
recieved:SCALAR(0x12bc71c0) len=0 ''

那么为什么看起来对 sv_setpvn 的 perl 调用失败或不起作用? 我不知道为什么当我在 perl 中打印返回的二进制数据时,它显示为一个空标量,但在 SWIG C++ 嵌入式类型映射中看起来很好。

我正在使用:

为 x86_64-linux-thread-multi 构建的 Perl v5.8.8

SWIG 2.0.1

gcc 版本 4.1.1 20070105(红帽 4.1.1-52)

【问题讨论】:

    标签: perl binary char swig unsigned


    【解决方案1】:

    在 Perl 方面,你能补充一下吗

    use Devel::Peek;
    Dump($fr->swig_data_get());
    

    并提供输出?谢谢。

    【讨论】:

    • get binary_data '1234567890' [10] (0x186BC4E0) 用法:Devel::Peek::Dump(sv, lim=4) at ./Test_swig_binary.t line 20.
    • @user297500,就好像什么都没有返回。这怎么可能?!如果你在某个地方上传了一个压缩包,我会试试看。
    • $result = obj; //HACK: SWIG YOU ARE SUPPOST TO DO THIS, OR AT LEAST DOCUMENT IT // This is needed for the swig generated perl to function correctly. argvi++; //现在可以使用了,感谢您的帮助。添加“argvi++;” "$result = obj" 之后的语句更正了问题。我注意到使用 SWIG 创建的所有其他 getter 方法都将此语句放在包装器 cxx 代码中。
    【解决方案2】:

    如果你不让它成为凡人呢?我正在使用 Inline::C 进行测试(因为我从未使用过 SWIG),并且将 SV 设置为 mortal 会导致问题,因为 Inline::C 正在为我做这件事。也许 SWIG 使用了类似的设计?

    两者

    SV* obj = newSV(0);
    sv_setpvn(obj, "abc", 3);
    

    SV* obj = newSVpvn("abc", 3);
    

    使用 Inline::C.

    【讨论】:

    • 谢谢。我尝试用这两种不同的构造方法替换 new_mortal 调用,但仍然得到相同的结果。
    【解决方案3】:

    如果您替换 %typemap(out) 中的以下行:

    $result = obj;
    

    $result = obj; argvi++;  //This is a hack to get the hidden stack pointer to increment before the return
    

    SWIG 生成的代码现在看起来像:

    ...
      ST(argvi) = obj; argvi++;
    }
    XSRETURN(argvi);
    }
    

    您的测试脚本将按预期返回 Perl 字符串。

    SV = PV(0x1eae7d40) at 0x1eac64d0
      REFCNT = 1
      FLAGS = (PADBUSY,PADMY,POK,pPOK)
      PV = 0x1eb25870 "1234567890"\0
      CUR = 10
      LEN = 16
    <<<PERL: swig_data_get
    sent    :SCALAR(0x1ea64530) len=10 '1234567890'
    recieved:SCALAR(0x1eac64d0) len=10 '1234567890'
    

    您应该更仔细地阅读关于 Perl 类型映射的 SWIG 2.0 文档:

    " 30.8.2 返回值

    返回值放置在每个包装函数的参数堆栈中。参数堆栈指针的当前值包含在变量 argvi 中。每当添加新的输出值时,增加该值至关重要。对于多个输出值,argvi的最终值应该是输出值的总数。 "

    【讨论】:

      【解决方案4】:

      swig 提供了一个名为 cdata.i 的模块。 您应该将其包含在接口定义文件中。

      一旦包含这个,它就会提供两个函数cdata()memmove()。给定一个 void * 和二进制数据的长度,cdata() 将其转换为目标语言的字符串类型。

      memmove() 是相反的。给定一个字符串类型,它会将字符串的内容(包括嵌入的空字节)复制到 C void* 类型中。

      使用此模块处理二进制数据变得非常简单。

      我希望这是你需要的。

      【讨论】:

        猜你喜欢
        • 2018-03-11
        • 2013-05-27
        • 1970-01-01
        • 2010-11-15
        • 2012-06-22
        • 2021-04-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多