gpt4 book ai didi

perl - 通过 FFI::Platypus 在 Perl 中获取缓冲区的大小

转载 作者:行者123 更新时间:2023-12-04 09:15:00 27 4
gpt4 key购买 nike

我正在使用 FFI::Platypus 来调用 C 函数。该函数有四个参数:两个字符串、一个指向缓冲区的指针和缓冲区大小:

int helper_getAddr(
const char *firstName,
const char *lastName,
char **address,
size_t *addressLen);
我通过 FFI::Platypus 像这样定义它:
$self->{ffi}->attach( [helper_getAddr => 'get_addr']
=> ['string', 'string', 'string', 'size_t'] => 'int' );
然后像这样调用:
my $contents_ptr = malloc 100;
my $size;
my $success = get_addr( "Tom", "Baker", \$contents_ptr, \$size );
所以我可以使用 buffer_to_scalar获取缓冲区内容。
调用似乎有效 - $success = 0$contents_ptr已定义 - 但 $size未设置。
我很少使用 C/C++,所以我不确定我的问题是否在 $size 的声明中。 ,或者如果我需要将电话更改为 get_addr() .
或者,有没有办法可以使用 $contents_ptr在我调用 buffer_to_scalar 之前直接在 Perl 中查找缓冲区的长度?

最佳答案

以下是不正确的:

[ 'string', 'string', 'string', 'size_t' ]
  • helper_getAddr的第三个参数不是字符串。
  • helper_getAddr的第四个参数不是 size_t .

  • 在继续之前,我们必须确定函数期望什么。这是有问题的,因为函数的参数没有多大意义。
    helper_getAddr填充现有的缓冲区,我希望
    int helper_getAddr(
    const char *firstName,
    const char *lastName,
    char **address,
    size_t *addressLen
    );
    helper_getAddr分配并返回一个字符串,我希望
    char *helper_getAddr(
    const char *firstName,
    const char *lastName
    );
    或者
    int helper_getAddr(
    const char *firstName,
    const char *lastName,
    char **address
    );
    除了有一个额外无用的论点, helper_getAddr最类似于分配和返回字符串的函数。所以我将在 helper_getAddr 的假设下继续。分配并返回一个字符串。

    鉴于我们拥有的功能,我们很想使用以下内容:
    $ffi->attach(
    [ 'helper_getAddr' => '_get_addr' ],
    [ 'string', 'string', 'string*', 'size_t*' ], # XXX
    'int',
    );
    问题在于它不能让我们访问需要释放的指针。因此,我们将使用
    $ffi->attach(
    [ 'helper_getAddr' => '_get_addr' ],
    [ 'string', 'string', 'opaque*', 'size_t*' ],
    'int',
    );
    一个简单的包装器将使函数具有 Perl 风格的外观并处理释放缓冲区。
    sub get_addr {
    _get_addr($_[0], $_[1], \my $buf, \my $buf_size)
    or return undef;

    my $addr = $ffi->cast('opaque' => 'string', $buf);
    free($buf);
    return $addr;
    }
  • 我们不叫malloc在 Perl 中,因为该函数会简单地覆盖指针,从而导致内存泄漏。
  • 通过将缓冲区强制转换为 string类型,Platypus::FFI 将从返回缓冲区的以 NUL 结尾的内容创建一个 Perl 字符串,因此不需要 buffer_to_scalar任何一个。

  • 用法示例:
    say get_addr("Tom", "Baker") // "[undef]";
    完整的解决方案如下。

    lookup
    #!/home/ikegami/usr/perlbrew/perls/5.32.0t/bin/perl

    use strict;
    use warnings;
    use feature qw( say state );

    use FindBin qw( $RealBin );

    use FFI::Platypus qw( );
    use FFI::Platypus::Memory qw( free );

    my $ffi = FFI::Platypus->new( api => 1 );
    $ffi->find_lib(
    lib => 'lookup',
    libpath => $RealBin,
    );

    $ffi->attach(
    [ 'get_addr' => '_get_addr' ],
    [ 'string', 'string', 'opaque*', 'size_t*' ],
    'int',
    );

    sub get_addr {
    _get_addr($_[0], $_[1], \my $buf, \my $buf_size)
    or return undef;

    my $addr = $ffi->cast('opaque' => 'string', $buf);
    free($buf);
    return $addr;
    }

    say get_addr("Tom", "Baker") // "[undef]";
    liblookup.c
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>

    int get_addr(
    const char *first_name,
    const char *last_name,
    char **address_ptr,
    size_t *address_size_ptr
    ) {
    const char *prefix = "Address of ";

    const size_t len_prefix = strlen(prefix);
    const size_t len_f_n = strlen(first_name);
    const size_t len_l_n = strlen(last_name);

    *address_size_ptr = len_prefix + len_f_n + 1 + len_l_n + 1;
    *address_ptr = malloc(*address_size_ptr);
    if (!*address_ptr)
    return 0;

    char *p = *address_ptr;
    memmove(p, prefix, len_prefix); p += len_prefix;
    memmove(p, first_name, len_f_n); p += len_f_n;
    *p = ' '; ++p;
    memmove(p, last_name, len_l_n); p += len_l_n;
    *p = 0; ++p;

    return 1;
    }
    run
    #!/bin/bash
    trap 'printf '\''error!\n'\''; exit 1' ERR

    script="$( readlink -e -- "$0" )"
    script_dir="$( dirname -- "$script" )"
    home_dir="$script_dir"
    cd "$home_dir"

    prog=./lookup

    # Use the PATH to locate the program.
    prog="$( which -- "$prog" )"

    # Use the program's shebang to locate the appropriate perl.
    perl="$( perl -ne'chomp; print s/^#!//r; exit;' "$prog" )"

    # Extract compiler and linker information from the correct perl.
    get_config() { "$perl" -MConfig -e'print $Config{$ARGV[0]}' "$1"; }
    cc="$( get_config cc )"
    ccflags="$( get_config ccflags )"
    optimize="$( get_config optimize )"
    cccdlflags="$( get_config cccdlflags )"
    ld="$( get_config ld )"
    lddlflags="$( get_config lddlflags )"

    # Build the shared library.
    "$cc" -c $ccflags $optimize $cccdlflags liblookup.c -o liblookup.o
    "$ld" $lddlflags liblookup.o -o liblookup.so

    # Run our test.
    "$prog"

    关于perl - 通过 FFI::Platypus 在 Perl 中获取缓冲区的大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63271072/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com