malloc’ing strcat

Florian Weimer fweimer@redhat.com
Mon Feb 24 21:17:00 GMT 2020


* Alexandre François Garreau:

> Not any more than the current standard strcat functions, which more or 
> less behaves the same (except my macro doesn’t buffer overflow, and is not 
> destructive, but I could as well make a version that is destructive as 
> well using realloc that would fail for a statically allocated first 
> argument):
> #define astrcat(a, b) strcat (realloc (a, strlen(a) + strlen (b) + 1), b)
>
> The most often use is to concatenate two strings at a time anyway, so it’s 
> already a big step forward to have a self contained interface, rather than 
> always repetitively calling malloc with the same arguments and often with 
> strcpy combined…

That doesn't match what I see.  After all, without garbage collection,
you can't do this:

  astrcat (astract (a, b), c)

And multi-concatenations are fairly common:

  <https://codesearch.debian.net/search?q=stpcpy.*stpcpy.*stpcpy&literal=0>

>> > But I’m curious, what did C11 change about that?
>> 
>> It's possible to use a variadic macro and a compound literal to
>> construct an array in a macro, and pass that (along with the array size)
>> to the actual implementation in a function (whose name would be an
>> implementation detail).
>
> Ohhhh, you mean the function-arg-separators commas would become arrays-
> separators commas, like that?
> #define astrcat(...) _astrcat((char *[]) {__VA_ARGS__, NULL})
> char *
> _astrcat (char *strarray[])
> {
>   char * result = malloc(1);
>   size_t len = 1;
>   off_t i = -1;
>   result[0] = '\0';
>   while (strarray[++i])
>   result = strcat(realloc(result, len += strlen(strarray[i])), 
> strarray[i]);
>   return result;
> }

I think I wouldn't use the NULL sentinel for the reasons indicated
(silent truncation after memory allocation or other failure, even under
valgrind), and use

  sizeof ((const char *[]) { __VA_ARGS__ }) / sizeof (const char *)

to compute the number of arguments, and pass that separately from the
pointer.

>> I don't think this could be done in a portable manner before C11.
>
> Why couldn’t a standard variadic function do? it’s only longer:
> #define astrcat(...) _astrcat (__VA_ARGS__, NULL)

Yes, I meant C99.  Compound literals and __VA_ARGS__ were added in C99.

>> > And still, why wasn’t a macro such as the one I presented already
>> > introduced?
>> 
>> strdup was only recently added to ISO C, and POSIX is somewhat dormant
>> these days.
>
> but there were already convenient functions before standardizations 
> weren’t they? such as the scanf “m” (or “a” I forgot) conversion modifier, 
> or vasprintf… right?

asprintf is still a GNU extension.  The m scanf modifier is only in
POSIX.

Thanks,
Florian



More information about the Libc-help mailing list