我试图让我更容易在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.8SWIG 2.0.1
gcc版本4.1.1 20070105(Red Hat 4.1.1-52)
答案 0 :(得分:2)
如果替换%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的最终值应为输出值的总数。 “
答案 1 :(得分:1)
如果你没有使它成为凡人怎么办?我正在使用Inline :: C进行测试(因为我从未使用过SWIG),并且因为Inline :: C正在为我做这件事,因此将SV设置为凡人造成了问题。也许SWIG使用类似的设计?
两个
SV* obj = newSV(0);
sv_setpvn(obj, "abc", 3);
和
SV* obj = newSVpvn("abc", 3);
使用Inline :: C。
答案 2 :(得分:1)
swig提供了一个名为cdata.i
的模块。
您应该在接口定义文件中包含它。
包含此内容后,它会提供两个函数cdata()
和memmove()
。给定void *和二进制数据的长度,cdata()
将其转换为目标语言的字符串类型。
memmove()
正好相反。给定一个字符串类型,它会将字符串的内容(包括嵌入的空字节)复制到C void *类型中。
使用此模块处理二进制数据变得非常简单。
我希望这是你需要的。
答案 3 :(得分:0)
在Perl方面,你可以添加
use Devel::Peek;
Dump($fr->swig_data_get());
并提供输出?感谢。