代码之家  ›  专栏  ›  技术社区  ›  airween

SWIG typedef-Perl数组

  •  2
  • airween  · 技术社区  · 8 年前

    我有一个SWIG文件,可以为语言创建许多绑定。C源代码中有一个变量,它是一个整数类型的固定长度列表。当我在Perl中访问它时,它没有任何项-只是显示它是一个ARRAY。

    Python也有同样的问题,但我可以用SWIG类型图修复:

    #ifdef SWIGPYTHON
    %typemap(out) int [ANY] {
       ...
    

    好的,我想用Perl再做一次,但我不是Perl专家,所以我可以为Perl修复这个类型映射。这就是我尝试的:

    #ifdef SWIGPERL
    %typemap(out) int [ANY] {
        SV* sv = newSV(0);
        AV* av = (AV *)sv_2mortal((SV *)newAV());
        int i = 0,len = 0;
        printf("len: %d\n", $1_dim0);
        len = $1_dim0;
    
        for (i = 0; i < len ; i++) {
            SV* perlval = newSV(0);
            sv_setiv(perlval, (IV)$1[i]);
            av_push(av, perlval);
        }
        SvSetSV($result, newRV_noinc((SV *)av));
    }
    #endif
    

    perl脚本在运行时向我显示“len:10”,但数组为空:

    $i=1;
    foreach(@m) {
        print $i, "'", $_, "'\n";
        $i=$i+1;
    }
    

    结果是:

    0''

    他们缺什么?

    谢谢

    编辑:这是Perl脚本:

    #!/usr/bin/perl
    
    use example1;
    
    # this function set up the built-in list in example1 module
    example1::get_att(7);
    my @m = $example1::m->{ilist};
    
    # "m" is a C structure in C source, and it has an "int ilist[10];" member.
    # get_att(int n) will fill this list with "n" number
    # This will be accesable in binded lanugage (eg in Python) as like this:
    # print m.ilist  -> [0, 3, 6, 9, 12, 15, 18, 0, 0, 0]
    $i = 0;
    foreach(@m) {
        print $i, "'", $_, "'\n";
        $i=$i+1;
    }
    

    现在,此脚本生成以下结果:

    len: 10
    0''
    

    “len:10”输出来自SWIG typedef-请参阅“printf(“len:%d…”行。。。

    1 回复  |  直到 8 年前
        1
  •  1
  •   Håkon Hægland    8 年前

    我以前没有使用过SWIG,但我想了解一下它可能会很有趣。在阅读了 documentation 几个小时以来,我想我可能已经找到了解决你问题的方法。首先我们需要接口文件 example.i :

    %module example
    
    %typemap(out) int [ANY] {
        AV* av = newAV();
        int i = 0,len = 0;
        len = $1_dim0;
    
        for (i = 0; i < len ; i++) {
            SV* perlval = newSV(0);
            sv_setiv(perlval, (IV)$1[i]);
            av_push(av, perlval);
        }
        $result = newRV_noinc((SV*) av );
        sv_2mortal( $result );
        argvi++;
    }
    
    %typemap(in) int [ANY] {
      AV *tempav;
      I32 len;
      int i;
      SV  **tv;
      if (!SvROK($input))
        croak("Argument $argnum is not a reference.");
      if (SvTYPE(SvRV($input)) != SVt_PVAV)
        croak("Argument $argnum is not an array.");
      tempav = (AV*)SvRV($input);
      len = av_len(tempav);
      $1 = (int *) malloc((len+1)*sizeof(int));
      for (i = 0; i <= len; i++) {
        tv = av_fetch(tempav, i, 0);
        $1[i] = (int) SvIV(*tv);
      }
    }
    
    %typemap(freearg) int * {
      free($1);
    }
    
    %typemap(memberin) int [ANY] {
      int i;
      for (i = 0; i < $1_dim0; i++) {
          $1[i] = $input[i];
      }
    }
    
    %inline %{
    
    struct m {
        int ilist[3];
    };
    
    %}
    

    然后,我们需要创建一个Perl脚本来测试 example::m 包裹:

    use feature qw(say);
    use strict;
    use warnings;
    
    use example;
    
    my $m = example::m->new();
    $m->{ilist} = [1, 2, 3];
    my $list = $m->{ilist};
    
    my $i = 0;
    for ( @$list ) {
        say "$i: '$_'";
        $i=$i+1;
    }
    

    现在输出(编译接口文件并运行Perl脚本后):

    0: '1'
    1: '2'
    2: '3'
    

    笔记 :

    • 我第一次安装SWIG 3.0.8(在Ubuntu 16.04上)是使用

      $ sudo apt-get install swig
      
    • 然后我编译了接口文件 示例.i 使用:

      $ swig -perl5 example.i
      $ gcc -fpic -c -Dbool=char -D_GNU_SOURCE \ 
         -I/usr/lib/x86_64-linux-gnu/perl/5.22/CORE example_wrap.c
      $ gcc -shared example.o example_wrap.o -o example.so