malloc’ing strcat
Alexandre François Garreau
galex-713@galex-713.eu
Mon Feb 24 20:23:00 GMT 2020
Le lundi 24 février 2020, 13:38:32 CET Florian Weimer a écrit :
> * Alexandre François Garreau:
> > Le lundi 24 février 2020, 12:16:54 CET Florian Weimer a écrit :
> >> * Alexandre François Garreau:
> >> > strcat needs a buffer already wide enough to contain concatenation
> >> > of
> >> > both strings, hence I deduce idiomatic use is to first
> >> > malloc(strlen(str1) + strlen(str2) + 1)…
> >> >
> >> > But then the usage must always be something like:
> >> > #define strcat(a, b) strcat (strcpy (malloc (strlen(a) + strlen (b)
> >> > +
> >> > 1) a), b)
> >> > (which, of course, requires further free())…
> >> >
> >> > So is there already a function or macro which does that? if not so,
> >> > why?
> >>
> >> One reason could be that before C11 (and C++11), it was difficult to
> >> implement in a portable manner. You would have to use a variadic
> >> function with a sentinel argument, and NULL as the most obvious (and
> >> most portable) choice for the sentinel could silently truncate the
> >> argument list if one of the arguments is specified incorrectly as
> >> NULL.
> >
> > I didn’t even talk about something variadic (my example macro has a
> > fixed (2) valence)… but even so taking care about NULL to make
> > variadicity to works looks reasonable to me…
>
> The two-argument restriction seems rather arbitrary.
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…
> > 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 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)
char *
_astrcat (char * str, ...)
{
va_list ap;
size_t len = strlen(str)+1;
char *arg, *result = malloc(len);
strcpy(result, str);
va_start(ap, str);
while (arg = va_arg(ap, char*))
result = strcat(realloc(result, len += strlen(arg)), arg);
va_end(ap);
return result;
}
I tried these and they work, without appearing to be specially non-
standard to me…
> > 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?
I mean, glibc have extensions and doesn’t have to be the standard and only
the standard, afaik
More information about the Libc-help
mailing list