【问题标题】:NativeCall Struct which contains Pointer包含指针的 N​​ativeCall 结构体
【发布时间】:2016-02-06 21:13:06
【问题描述】:

我有以下结构:

typedef struct _info{
  DWORD myInfo;
  BYTE  *pInfo;
  LPWSTR ExtData;

} Info;

我使用NativeCall 表示这个结构体:

class Info is repr('CStruct') {
    has int32 $.myInfo;
    has Pointer[int8] $.pInfo ; 
    has Pointer[int16] $.ExtData;
}

这种表示可以吗?如何访问和设置$.pInfo指向的数据?

【问题讨论】:

    标签: raku nativecall


    【解决方案1】:

    对我来说,这种表示似乎没问题...鉴于这个发明的 C 库: (请不要挑剔我的 C foo - 这不是重点)

    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    
    typedef unsigned long int DWORD;
    typedef unsigned char BYTE;
    typedef char * LPWSTR;
    
    typedef struct _info{
      DWORD   myInfo;
      BYTE   *pInfo;
      LPWSTR  ExtData;
    } Info;
    
    
    Info* create_info();
    void  display_info();
    void  double_info(Info*);
    
    Info*
    create_info() {
        DWORD init_myinfo    = 2016;
        BYTE  init_pinfo     = 37;
        char  init_ExtData[] = "Hello World";
    
        Info *new_info = malloc(sizeof(Info));
        if (new_info == NULL) {
            printf( "Memory alloc failed\n" );
            exit(1);
        }
    
        new_info->myInfo = init_myinfo;
    
        BYTE *pinfo = malloc(sizeof(BYTE));
        *pinfo = init_pinfo;
        new_info->pInfo = pinfo;
    
        char *ext_data = malloc(sizeof(init_ExtData));
        strcpy(ext_data, init_ExtData);
        new_info->ExtData = ext_data;
    
        return new_info;
    }
    
    void
    display_info(Info *inf) {
        printf("myInfo: %lu\n", inf->myInfo);
        printf("pInfo:  %i\n", *inf->pInfo);
        printf("ExtData: %s\n", inf->ExtData);
    }
    
    void
    double_info(Info *inf) {
    
        inf->myInfo *=  2;
    
        if ( *(inf->pInfo) < 128 )
            *(inf->pInfo) *= 2;
    
        int extdata_len = strlen(inf->ExtData);
        char *tmp_extdata = malloc(extdata_len * 2 + 2);
        strncpy(tmp_extdata, inf->ExtData, extdata_len);
        tmp_extdata[extdata_len] = '+';
        strcpy(&tmp_extdata[extdata_len+1], inf->ExtData);
        inf->ExtData = tmp_extdata;
    }
    

    那么您使用 NativeCall 的 perl6 结构定义或多或少可以工作:

    #!/usr/bin/env perl6
    use NativeCall;
    
    class Info is repr('CStruct') {
        has int32          $.myInfo;
        has Pointer[int8]  $.pInfo ;
        has Pointer[Str]   $.ExtData;
    
        method Str {
          qq:to/END HERE/;
          myInfo: $!myInfo
          pInfo: { $!pInfo.deref }
          ExtData: { $!ExtData.deref }
          END HERE
        }
    }
    
    our sub create_info()  returns Info is native('pinfo') { * }
    our sub display_info(Info) is native('pinfo') { * }
    our sub double_info(Info is rw) is native('pinfo') { * }
    
    my Info $inf = create_info();
    say 'Displaying $inf after calling create_info()';
    display_info $inf;
    
    double_info $inf;
    say 'Displaying $inf after calling double_info()';
    display_info $inf;
    
    say 'Displaying $inf by calling attribute methods on Perl6 object';
    say "myInfo: $inf.myInfo()";
    say "pInfo: $inf.pInfo.deref()";
    say "ExtData: $inf.ExtData.deref()";
    
    say 'Displaying $inf by stringifying Perl6 object';
    say "$inf";
    exit 0;
    

    这样的运行产生;

    Displaying $inf after calling create_info()
    myInfo: 2016
    pInfo:  37
    ExtData: Hello World
    Displaying $inf after calling double_info()
    myInfo: 4032
    pInfo:  74
    ExtData: Hello World+Hello World
    Displaying $inf by calling attribute methods on Perl6 object
    myInfo: 4032
    pInfo: 74
    ExtData: Hello World+Hello World
    Displaying $inf by stringifying Perl6 object
    myInfo: 4032
    pInfo: 74
    ExtData: Hello World+Hello World
    

    或者,可以在 perl6 类中隐藏更多的“胶水”;

    #!/usr/bin/env perl6
    use NativeCall;
    
    class Info is repr('CStruct') {
        has int32          $.myInfo is rw ;
        has Pointer[int8]  $!pInfo ;
        has Pointer[Str]   $!ExtData ;
    
        my sub create_info() returns Info is native('pinfo') { * }
        my sub display_info(Info)         is native('pinfo') { * }
        my sub double_info(Info is rw)    is native('pinfo') { * }
    
        method new     {  create_info()      }
        method display {  display_info(self) }
        method double  {  double_info(self)  }
    
        method pInfo   {  $!pInfo.deref      }
        method ExtData {  $!ExtData.deref    }
    
        method Str {
            qq:to/END HERE/;
            myInfo: {  self.myInfo  }
            pInfo: {   self.pInfo   }
            ExtData: { self.ExtData }
            END HERE
        }
    }
    
    my Info $inf .= new;
    say 'Displaying $inf after calling .new';
    $inf.display ;
    
    $inf.double ;
    say 'Displaying $inf after calling .double';
    $inf.display ;
    
    say 'Displaying $inf by calling attribute methods on Perl6 object';
    say "myInfo: $inf.myInfo()";
    say "pInfo: $inf.pInfo()";
    say "ExtData: $inf.ExtData()";
    
    $inf.myInfo = 12046 ;
    say 'Displaying $inf by stringifying Perl6 object';
    say "$inf";
    exit 0;
    

    ...更干净的外观。它同样产生;

    Displaying $inf after calling .new
    myInfo: 2016
    pInfo:  37
    ExtData: Hello World
    Displaying $inf after calling .double
    myInfo: 4032
    pInfo:  74
    ExtData: Hello World+Hello World
    Displaying $inf by calling attribute methods on Perl6 object
    myInfo: 4032
    pInfo: 74
    ExtData: Hello World+Hello World
    Displaying $inf by stringifying Perl6 object
    myInfo: 12046
    pInfo: 74
    ExtData: Hello World+Hello World
    

    注意事项:

    (1) 对 Pointer 类型的属性调用 .deref() 方法来获取指向的实际数据。

    (2) NativeCall documentation 必须多次阅读;-)

    (3) 无论我如何尝试,我都无法修改通过指针引用的数据 - 我不断收到“无法修改不可变数据”。

    (4) YMMV

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-04-06
      • 1970-01-01
      • 1970-01-01
      • 2020-11-25
      • 1970-01-01
      • 2018-05-30
      • 2021-07-28
      相关资源
      最近更新 更多