Hi Stefan, On 12/16/22 19:47, Stefan Puiu wrote: > Hi Alex! > > On Thu, Dec 15, 2022 at 2:46 AM Alejandro Colomar > wrote: >> >> Formatted strpcy(3): >> >> strcpy(3) Library Functions Manual strcpy(3) >> >> NAME >> strcpy - copy or catenate a string >> >> LIBRARY >> Standard C library (libc, -lc) >> >> SYNOPSIS >> #include >> >> char *stpcpy(char *restrict dst, const char *restrict src); >> char *strcpy(char *restrict dst, const char *restrict src); >> char *strcat(char *restrict dst, const char *restrict src); >> >> Feature Test Macro Requirements for glibc (see feature_test_macros(7)): >> >> stpcpy(): >> Since glibc 2.10: >> _POSIX_C_SOURCE >= 200809L >> Before glibc 2.10: >> _GNU_SOURCE >> >> DESCRIPTION >> stpcpy() >> strcpy() >> These functions copy the string pointed to by src, into a string >> at the buffer pointed to by dst. The programmer is responsible >> for allocating a buffer large enough, that is, strlen(src) + 1. >> They only differ in the return value. > > A destination buffer large enough? It's not that obvious to me from > the text, but maybe I'm tired :). Sure. Thanks! > I was also a bit at a loss about the difference between the two; maybe > you can say "For the difference between the two, see RETURN VALUE"? That can make sense, yes. > >> >> strcat() >> This function catenates the string pointed to by src, at the end >> of the string pointed to by dst. The programmer is responsible >> for allocating a buffer large enough, that is, strlen(dst) + >> strlen(src) + 1. > > Ditto here. :) > >> >> An implementation of these functions might be: >> >> char * >> stpcpy(char *restrict dst, const char *restrict src) >> { >> char *end; >> >> end = mempcpy(dst, src, strlen(src)); >> *end = '\0'; >> >> return end; >> } >> >> char * >> strcpy(char *restrict dst, const char *restrict src) >> { >> stpcpy(dst, src); >> return dst; >> } >> >> char * >> strcat(char *restrict dst, const char *restrict src) >> { >> stpcpy(dst + strlen(dst), src); >> return dst; >> } > > Are you sure this section adds any value? I think good documentation > should explain how a function works without delving into the > interpretation. To be honest, this page doesn't benefit too much from it. strcpy(3)/strcat(3) are dead simple, and the explanations above should be enough. However, the same thing in strncpy(3) and strncat(3) is very helpful, IMO. For consistency I just showed trivial implementations in all of the pages. (And in fact, there was an example implementation in the old strncat(3) and maybe a few others, IIRC.) > Also, people might get confused and think this is the > actual implementation. I don't think there's any problem if one believes this is the implementation. Except for stpcpy(3), in which I preferred readability, they are actually quite good implementations. A faster implementation of stpcpy(3) might be done in terms of memccpy(3). Funnily enough, I just checked what musl libc does, and it's the same as shown here: alx@debian:~/src/musl/musl$ grepc -tfd strcpy ./src/string/strcpy.c:3: char *strcpy(char *restrict dest, const char *restrict src) { __stpcpy(dest, src); return dest; } alx@debian:~/src/musl/musl$ grepc -tfd strcat ./src/string/strcat.c:3: char *strcat(char *restrict dest, const char *restrict src) { strcpy(dest + strlen(dest), src); return dest; } > >> >> RETURN VALUE >> stpcpy() >> This function returns a pointer to the terminating null byte at >> the end of the copied string. >> >> strcpy() >> strcat() >> These functions return dest. >> >> ATTRIBUTES >> For an explanation of the terms used in this section, see attrib‐ >> utes(7). >> ┌────────────────────────────────────────────┬───────────────┬─────────┐ >> │Interface │ Attribute │ Value │ >> ├────────────────────────────────────────────┼───────────────┼─────────┤ >> │stpcpy(), strcpy(), strcat() │ Thread safety │ MT‐Safe │ >> └────────────────────────────────────────────┴───────────────┴─────────┘ >> >> STANDARDS >> stpcpy() >> POSIX.1‐2008. >> >> strcpy() >> strcat() >> POSIX.1‐2001, POSIX.1‐2008, C89, C99, SVr4, 4.3BSD. >> >> CAVEATS >> The strings src and dst may not overlap. >> >> If the destination buffer is not large enough, the behavior is unde‐ >> fined. See _FORTIFY_SOURCE in feature_test_macros(7). >> >> BUGS >> strcat() >> This function can be very inefficient. Read about Shlemiel >> the painter ⟨https://www.joelonsoftware.com/2001/12/11/ >> back-to-basics/⟩. > > I'm not sure this is a bug, rather a design limitation. Maybe it > belongs in NOTES or CAVEATS? Yeah, I had been thinking of downgrading it. I'll do it. > Also, I think this can be summarized > along the lines of 'strcat needs to walk the destination buffer to > find the null terminator, so it has linear complexity with respect to > the size of the destination buffer up to the terminator' (hmm, I'm > sure this can be expressed more concisely), so the page is more self > contained. Outside links sometimes go dead, like on Wikipedia, so I > think just in case, it helps to make explicit the point that you want > the reader to study further in the URL. I wasn't inspired to write it short enough to not be too verbose. Maybe I'll write something based on your suggestion. > > Regards, > Stefan. Thanks for the review! Cheers, Alex > >> >> EXAMPLES >> #include >> #include >> #include >> >> int >> main(void) >> { >> char *p; >> char buf1[BUFSIZ]; >> char buf2[BUFSIZ]; >> size_t len; >> >> p = buf1; >> p = stpcpy(p, "Hello "); >> p = stpcpy(p, "world"); >> p = stpcpy(p, "!"); >> len = p - buf1; >> >> printf("[len = %zu]: ", len); >> puts(buf1); // "Hello world!" >> >> strcpy(buf2, "Hello "); >> strcat(buf2, "world"); >> strcat(buf2, "!"); >> len = strlen(buf2); >> >> printf("[len = %zu]: ", len); >> puts(buf2); // "Hello world!" >> >> exit(EXIT_SUCCESS); >> } >> >> SEE ALSO >> strdup(3), string(3), wcscpy(3), string_copy(7) >> >> Linux man‐pages (unreleased) (date) strcpy(3) >> >> -- >> --