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
lenindicates 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?
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With