perlxs

How to pass length of a string argument to CODE section in XS?


In XS I can pass the length of a string argument to a C function using the length keyword:

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

MODULE = Foo        PACKAGE = Foo

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

However how can I get the length of the string if I need it inside the CODE block?

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

I can use STRLEN_length_of_s or XSauto_length_of_s variable autogenerated by xsubpp but it feels a bit hardcoded. Is there a way (possibly a predefined macro) I can use to get the variable name? Or can I assign my own name to the length argument? Or do I need to resort to declaring the argument as SV * and then get the length myself with SvPV in CODE section?


Solution

  • First of all, if you're using char* in your XS prototype (and the default typemap), your code is buggy.

    You want

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

    or

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

    Remember that Perl strings are sequences of 32-bit or 64-bit numbers, while C strings are sequences of 8-bit chars.[1] Some conversion needs to occur, and you need to specify which one.

    In the first case, each character of the string will be a char of s.

    In the second case, s will be provided the Perl string encoded using utf8.


    1. Technically, a char can be larger than 8 bits, but I don't think it can be on systems supported by perl.