【问题标题】:How to pass length of a string argument to CODE section in XS?如何将字符串参数的长度传递给 XS 中的 CODE 部分?
【发布时间】:2018-03-07 12:22:45
【问题描述】:

在 XS 中,我可以使用 length keyword 将字符串参数的长度传递给 C 函数:

static int foo(const char *s, size_t len)
{
    return 1;
}

MODULE = Foo        PACKAGE = Foo

void
foo(char *s, STRLEN length(s))

但是,如果我需要在 CODE 块中获取字符串的长度,我该如何获取它?

void
foo(char *s, STRLEN length(s))
CODE:
    ...
    foo(s, ???);

我可以使用 STRLEN_length_of_sXSauto_length_of_s 自动生成的变量 xsubpp 但感觉有点硬编码。有没有办法(可能是预定义的宏)可以用来获取变量名?或者我可以将我自己的名字分配给长度参数吗?还是我需要将参数声明为SV *,然后自己在代码部分使用SvPV 获取长度?

【问题讨论】:

    标签: perl xs


    【解决方案1】:

    首先,如果您在 XS 原型(和默认类型映射)中使用 char*,那么您的代码有问题。

    你想要

    void
    foo(SV* sv)
    PREINIT:
        STRLEN len;
        char* s;
    CODE:
        s = SvPVbyte(sv, len);
        foo(s, len);
    

    void
    foo(SV* sv)
    PREINIT:
        STRLEN len;
        char* s;
    CODE:
        s = SvPVutf8(sv, len);
        foo(s, len);
    

    请记住,Perl 字符串是 32 位或 64 位数字的序列,而 C 字符串是 8 位字符的序列。[1] 需要进行一些转换,您需要指定哪个。

    在第一种情况下,字符串的每个字符都是chars

    在第二种情况下,s 将提供使用 utf8 编码的 Perl 字符串。


    1. 从技术上讲,char 可以大于 8 位,但我认为它不能在 perl 支持的系统上。

    【讨论】:

    • 您是说应该始终根据底层 C 函数显式选择字节或 utf-8 表示形式?默认类型映射使用不适合表示字符串的 SvPV,对吧?因此,您首选的方法是在参数中直接使用 SV 并在 PREINIT 部分中检索指针和长度。我认为长度关键字不是正确的方法。
    • Re "您是说应该始终根据底层 C 函数显式选择字节或 utf-8 表示形式?",还有第三种选择:使用@987654329 @ 与SvUTF8 一起确定SvPV 返回的缓冲区的编码。
    • Re "默认的typemap使用的是不适合表示字符串的SvPV,对吧?",当使用SvPV而不使用SvUTF8时,你不知道是什么你有。例如,当使用 SvPV 时,Perl 中的 "\xE9" 可能同样导致 C 中的 "\xE9\x00""\xC3\xA9\x00"
    • Re "So your prefer way",调整typemap同样可以接受。
    • 我不得不将SvPVxxx 调用移动到INIT 部分,因为在PREINIT 中,SV 参数还没有从堆栈中弹出,导致 'sv' 是未在此范围内声明错误。
    猜你喜欢
    • 1970-01-01
    • 2018-08-25
    • 1970-01-01
    • 2014-08-05
    • 2011-06-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多