没有副本的指针的 Perl SV 值

Perl SV value from pointer without copy

如何在不复制的情况下从空终止字符串创建 SV 值?与 newSVpv(const char*, STRLEN) 类似,但没有复制并将所有权移至 Perl(因此 Perl 必须释放该字符串内存)。我需要这个来避免大量的内存分配和复制。

我找到了以下示例:

SV *r = sv_newmortal();
SvPOK_on(r);
sv_usepvn_mg(r, string, strlen(string) + 1);

但我对XS的内部结构了解不深,有些疑惑。

如果你想让Perl 管理内存块,它需要知道如何重新分配和释放它。它唯一知道如何重新分配和解除分配的内存是使用其分配器 Newx 分配的内存。 (否则,它必须为每个内存块关联一个重新分配器和释放器。)

如果您不能使用 Newx 分配内存块,那么您最好的选择可能是创建一个只读 SV,并将 SvLEN 设置为零。这告诉 Perl 它不拥有内存。那个 SV 可以被祝福成一个 class,它有一个析构函数,可以使用适当的释放器释放内存。

如果您可以使用Newx分配内存块,那么您可以使用以下方法:

SV* newSVpvn_steal_flags(pTHX_ const char* ptr, STRLEN len, const U32 flags) {
#define newSVpvn_steal_flags(a,b,c) newSVpvn_steal_flags(aTHX_ a,b,c)
    SV* sv;

    assert(!(flags & ~(SVf_UTF8|SVs_TEMP|SV_HAS_TRAILING_NUL)));

    sv = newSV(0);
    sv_usepvn_flags(sv, ptr, len, flags & SV_HAS_TRAILING_NUL);
    if ((flags & SVf_UTF8) && SvOK(sv)) {
        SvUTF8_on(sv);
    }

    SvTAINT(sv);

    if (flags & SVs_TEMP) {
        sv_2mortal(sv);
    }

    return sv;
}

注意:ptr 应该指向由 Newx 分配的内存,并且它必须指向由 Newx 返回的块的开始。

注意:接受标志 SVf_UTF8(指定 ptr 是要在 Perl 中看到的字符串的 UTF-8 编码),SVs_TEMP(具有 sv_2mortal 在 SV 上调用)和 SV_HAS_TRAILING_NUL(见下文)。

注意:某些代码期望标量的字符串缓冲区具有尾随 NUL(即使缓冲区的长度已知并且即使缓冲区可以包含 NUL)。如果您分配的内存块在数据末尾有一个尾随 NUL(例如,C 风格的 NUL 终止字符串),则传递 SV_HAS_TRAILING_NUL 标志。如果不是,该函数将尝试扩展缓冲区并添加一个 NUL。