Search code examples
perlxs

What's the difference between sv_catpv() and sv_catpvs()?


According to perlapi, sv_catpv() works as follows:

Concatenates the NUL-terminated string onto the end of the string which is in the SV. If the SV has the UTF-8 status set, then the bytes appended should be valid UTF-8. Handles 'get' magic, but not 'set' magic.

void sv_catpv(SV *const sv, const char* ptr)

Most of the XS tutorials I've found use sv_catpvs(), though, which does this:

Like sv_catpvn, but takes a literal string instead of a string/length pair.

void sv_catpvs(SV* sv, const char* s)

Well, that's not very helpful, so let's look at sv_catpvn():

Concatenates the string onto the end of the string which is in the SV. The len indicates number of bytes to copy. If the SV has the UTF-8 status set, then the bytes appended should be valid UTF-8. Handles 'get' magic, but not 'set' magic.

void sv_catpvn(SV *dsv, const char *sstr, STRLEN len)

So, sv_catpvn does the same thing as sv_catpv except that it takes the string length as a separate parameter, and sv_catpvs is the same as sv_catpvn except it takes the literal string.

Is there some subtle difference between sv_catpv and sv_catpvs that I'm missing, or are they just two ways to do the same thing?


Solution

  • As per the passages you quoted, sv_catpvs only takes a string literal.

    const char *str = "foo";
    
    sv_catpvs(sv, "foo");   // ok
    sv_catpvs(sv, str);     // ERROR
    

    sv_catpv, on the other hand, accepts any expression that returns a string.

    sv_catpv(sv, "foo");    // ok
    sv_catpv(sv, str);      // ok
    

    So why does sv_catpvs exist at all? Because it's faster. The reason sv_catpvs takes only takes a string literal is that it's a macro that expands

    sv_catpvs(sv, "foo")
    

    into something similar to

    sv_catpvn_flags(sv, "foo", sizeof("foo")-1, SV_GMAGIC)
    

    which resolves to

    sv_catpvn_flags(sv, "foo", 3, SV_GMAGIC)
    

    at compile-time. sv_catpv, on the other hand, is forced to use slower strlen.