Welcome to Software Development on Codidact!
Will you help us build our independent community of developers helping developers? We're small and trying to grow. We welcome questions about all aspects of software development, from design to code to QA and more. Got questions? Got answers? Got code you'd like someone to review? Please join us.
Post History
After addressing @Lundin 's suggestions: Implemented in terms of libc functions for performance. const correctness style improvements I have a few more that I realized after trying to repla...
Answer
#10: Post edited
- After addressing @Lundin 's suggestions:
- - Implemented in terms of libc functions for performance.
- - const correctness
- - style improvements
- I have a few more that I realized after trying to replace some existing code:
- Much code out there has `char *end = buf + nitems(buf);` (although that should really be called `past_end`). That's certainly easier to calculate than the real `end` that I used here, since you don't need to stick that `-1` all around, and therefore has less chance of an accident.
- It's more readable at call site (due to alignment) when the `past_end` pointer is the second parameter to the function.
- So, I tweaked it to have the following definition:
- ```c
- char *
stpecpy(char *dst, char past_end[0],const char *restrict src)- {
- char *p;
- if (dst == past_end)
- return past_end;
- p = memccpy(dst, src, '\0', past_end - dst);
- if (p != NULL)
- return p - 1;
- /* truncation detected */
- past_end[-1] = '\0';
- return past_end;
- }
- ```
- To be clear, the return pointer is still the same: the pointer to the NUL byte on success, or one-past-the-array on truncation. It's only the last parameter that has changed to be a pointer one-past-the-array, which is simpler to get for users.
- The name of the function st**pe**cpy() seems to also have nice mnemonics for `past_end`.
- Now the use is slightly simpler:
- ```c
- int
- main(void)
- {
- ptrdiff_t size = 10;
- char buf[size];
- char *past_end, *p;
- ptrdiff_t len;
- past_end = &buf[size];
- p = buf;
- p = stpecpy(p, past_end, "Hello");
- p = stpecpy(p, past_end, " world");
- if (p == past_end) {
- p--;
- puts("Following string is truncated.");
- }
- len = p - buf;
- printf("%ti: %s\n", len, buf);
- p = buf;
- p = stpecpy(p, past_end, "Hello");
- p = stpecpy(p, past_end, " foo");
- p = stpecpy(p, past_end, "");
- if (p == past_end) {
- p--;
- puts("Following string is truncated.");
- }
- len = p - buf;
- printf("%ti: %s\n", len, buf);
- p = buf;
- p = stpecpy(p, past_end, "Hello");
- p = stpecpy(p, past_end, " baar");
- p = stpecpy(p, past_end, "");
- if (p == past_end) {
- p--;
- puts("Following string is truncated.");
- }
- len = p - buf;
- printf("%ti: %s\n", len, buf);
- p = buf;
- p = stpecpy(p, past_end, "H");
- p = stpecpy(p, past_end, "W");
- if (p == past_end) {
- p--;
- puts("Following string is truncated.");
- }
- len = p - buf;
- printf("%ti: %s\n", len, buf);
- }
- ```
- Which prints:
- ```c
- $ ./a.out
- Following string is truncated.
- 9: Hello wor
- 9: Hello foo
- Following string is truncated.
- 9: Hello baa
- 2: HW
- ```
- After addressing @Lundin 's suggestions:
- - Implemented in terms of libc functions for performance.
- - const correctness
- - style improvements
- I have a few more that I realized after trying to replace some existing code:
- Much code out there has `char *end = buf + nitems(buf);` (although that should really be called `past_end`). That's certainly easier to calculate than the real `end` that I used here, since you don't need to stick that `-1` all around, and therefore has less chance of an accident.
- It's more readable at call site (due to alignment) when the `past_end` pointer is the second parameter to the function.
- So, I tweaked it to have the following definition:
- ```c
- char *
- stpecpy(char *dst, char past_end[0], const char *restrict src)
- {
- char *p;
- if (dst == past_end)
- return past_end;
- p = memccpy(dst, src, '\0', past_end - dst);
- if (p != NULL)
- return p - 1;
- /* truncation detected */
- past_end[-1] = '\0';
- return past_end;
- }
- ```
- To be clear, the return pointer is still the same: the pointer to the NUL byte on success, or one-past-the-array on truncation. It's only the last parameter that has changed to be a pointer one-past-the-array, which is simpler to get for users.
- The name of the function st**pe**cpy() seems to also have nice mnemonics for `past_end`.
- Now the use is slightly simpler:
- ```c
- int
- main(void)
- {
- ptrdiff_t size = 10;
- char buf[size];
- char *past_end, *p;
- ptrdiff_t len;
- past_end = &buf[size];
- p = buf;
- p = stpecpy(p, past_end, "Hello");
- p = stpecpy(p, past_end, " world");
- if (p == past_end) {
- p--;
- puts("Following string is truncated.");
- }
- len = p - buf;
- printf("%ti: %s\n", len, buf);
- p = buf;
- p = stpecpy(p, past_end, "Hello");
- p = stpecpy(p, past_end, " foo");
- p = stpecpy(p, past_end, "");
- if (p == past_end) {
- p--;
- puts("Following string is truncated.");
- }
- len = p - buf;
- printf("%ti: %s\n", len, buf);
- p = buf;
- p = stpecpy(p, past_end, "Hello");
- p = stpecpy(p, past_end, " baar");
- p = stpecpy(p, past_end, "");
- if (p == past_end) {
- p--;
- puts("Following string is truncated.");
- }
- len = p - buf;
- printf("%ti: %s\n", len, buf);
- p = buf;
- p = stpecpy(p, past_end, "H");
- p = stpecpy(p, past_end, "W");
- if (p == past_end) {
- p--;
- puts("Following string is truncated.");
- }
- len = p - buf;
- printf("%ti: %s\n", len, buf);
- }
- ```
- Which prints:
- ```c
- $ ./a.out
- Following string is truncated.
- 9: Hello wor
- 9: Hello foo
- Following string is truncated.
- 9: Hello baa
- 2: HW
- ```
#9: Post edited
- After addressing @Lundin 's suggestions:
- - Implemented in terms of libc functions for performance.
- - const correctness
- - style improvements
I have one more that I realized after trying to replace some existing code:- Much code out there has `char *end = buf + nitems(buf);` (although that should really be called `past_end`). That's certainly easier to calculate than the real `end` that I used here, since you don't need to stick that `-1` all around, and therefore has less chance of an accident.
- So, I tweaked it to have the following definition:
- ```c
char *_Nonnullstpecpy(char *_Nonnull dst,const char *_Nonnull restrict src,char *_Nonnull past_end)- {
- char *p;
- if (dst == past_end)
- return past_end;
- p = memccpy(dst, src, '\0', past_end - dst);
- if (p != NULL)
- return p - 1;
- /* truncation detected */
- past_end[-1] = '\0';
- return past_end;
- }
- ```
- To be clear, the return pointer is still the same: the pointer to the NUL byte on success, or one-past-the-array on truncation. It's only the last parameter that has changed to be a pointer one-past-the-array, which is simpler to get for users.
- The name of the function st**pe**cpy() seems to also have nice mnemonics for `past_end`.
- Now the use is slightly simpler:
- ```c
- int
- main(void)
- {
- ptrdiff_t size = 10;
- char buf[size];
- char *past_end, *p;
- ptrdiff_t len;
- past_end = &buf[size];
p = stpecpy(stpecpy(buf, "Hello", past_end), " world", past_end);len = p - buf;- if (p == past_end) {
len--;- puts("Following string is truncated.");
- }
- printf("%ti: %s\n", len, buf);
p = stpecpy(stpecpy(stpecpy(buf, "Hello", past_end), " foo", past_end), "", past_end);len = p - buf;- if (p == past_end) {
len--;- puts("Following string is truncated.");
- }
- printf("%ti: %s\n", len, buf);
p = stpecpy(stpecpy(stpecpy(buf, "Hello", past_end), " baar", past_end), "", past_end);len = p - buf;- if (p == past_end) {
len--;- puts("Following string is truncated.");
- }
- printf("%ti: %s\n", len, buf);
p = stpecpy(stpecpy(buf, "H", past_end), "W", past_end);len = p - buf;- if (p == past_end) {
len--;- puts("Following string is truncated.");
- }
- printf("%ti: %s\n", len, buf);
- }
- ```
- Which prints:
- ```c
- $ ./a.out
- Following string is truncated.
- 9: Hello wor
- 9: Hello foo
- Following string is truncated.
- 9: Hello baa
- 2: HW
- ```
- After addressing @Lundin 's suggestions:
- - Implemented in terms of libc functions for performance.
- - const correctness
- - style improvements
- I have a few more that I realized after trying to replace some existing code:
- Much code out there has `char *end = buf + nitems(buf);` (although that should really be called `past_end`). That's certainly easier to calculate than the real `end` that I used here, since you don't need to stick that `-1` all around, and therefore has less chance of an accident.
- It's more readable at call site (due to alignment) when the `past_end` pointer is the second parameter to the function.
- So, I tweaked it to have the following definition:
- ```c
- char *
- stpecpy(char *dst, char past_end[0],
- const char *restrict src)
- {
- char *p;
- if (dst == past_end)
- return past_end;
- p = memccpy(dst, src, '\0', past_end - dst);
- if (p != NULL)
- return p - 1;
- /* truncation detected */
- past_end[-1] = '\0';
- return past_end;
- }
- ```
- To be clear, the return pointer is still the same: the pointer to the NUL byte on success, or one-past-the-array on truncation. It's only the last parameter that has changed to be a pointer one-past-the-array, which is simpler to get for users.
- The name of the function st**pe**cpy() seems to also have nice mnemonics for `past_end`.
- Now the use is slightly simpler:
- ```c
- int
- main(void)
- {
- ptrdiff_t size = 10;
- char buf[size];
- char *past_end, *p;
- ptrdiff_t len;
- past_end = &buf[size];
- p = buf;
- p = stpecpy(p, past_end, "Hello");
- p = stpecpy(p, past_end, " world");
- if (p == past_end) {
- p--;
- puts("Following string is truncated.");
- }
- len = p - buf;
- printf("%ti: %s\n", len, buf);
- p = buf;
- p = stpecpy(p, past_end, "Hello");
- p = stpecpy(p, past_end, " foo");
- p = stpecpy(p, past_end, "");
- if (p == past_end) {
- p--;
- puts("Following string is truncated.");
- }
- len = p - buf;
- printf("%ti: %s\n", len, buf);
- p = buf;
- p = stpecpy(p, past_end, "Hello");
- p = stpecpy(p, past_end, " baar");
- p = stpecpy(p, past_end, "");
- if (p == past_end) {
- p--;
- puts("Following string is truncated.");
- }
- len = p - buf;
- printf("%ti: %s\n", len, buf);
- p = buf;
- p = stpecpy(p, past_end, "H");
- p = stpecpy(p, past_end, "W");
- if (p == past_end) {
- p--;
- puts("Following string is truncated.");
- }
- len = p - buf;
- printf("%ti: %s\n", len, buf);
- }
- ```
- Which prints:
- ```c
- $ ./a.out
- Following string is truncated.
- 9: Hello wor
- 9: Hello foo
- Following string is truncated.
- 9: Hello baa
- 2: HW
- ```
#8: Post edited
- After addressing @Lundin 's suggestions:
- - Implemented in terms of libc functions for performance.
- - const correctness
- - style improvements
I have a couple that I realized after trying to replace some existing code:- Much code out there has `char *end = buf + nitems(buf);` (although that should really be called `past_end`). That's certainly easier to calculate than the real `end` that I used here, since you don't need to stick that `-1` all around, and therefore has less chance of an accident.
And, strlcpy(3) is fine for copying; this function only improves the status quo for concatenating, so it's better to name it appropriately: `stpecat()`.- So, I tweaked it to have the following definition:
- ```c
- char *_Nonnull
stpecat(char *_Nonnull dst,- const char *_Nonnull restrict src,
- char *_Nonnull past_end)
- {
- char *p;
- if (dst == past_end)
- return past_end;
- p = memccpy(dst, src, '\0', past_end - dst);
- if (p != NULL)
- return p - 1;
- /* truncation detected */
- past_end[-1] = '\0';
- return past_end;
- }
- ```
- To be clear, the return pointer is still the same: the pointer to the NUL byte on success, or one-past-the-array on truncation. It's only the last parameter that has changed to be a pointer one-past-the-array, which is simpler to get for users.
The name of the function st**pe**cat() seems to also have nice mnemonics for `past_end`.- Now the use is slightly simpler:
- ```c
- int
- main(void)
- {
- ptrdiff_t size = 10;
- char buf[size];
- char *past_end, *p;
- ptrdiff_t len;
- past_end = &buf[size];
p = stpecat(stpecpy(buf, "Hello", past_end), " world", past_end);- len = p - buf;
- if (p == past_end) {
- len--;
- puts("Following string is truncated.");
- }
- printf("%ti: %s\n", len, buf);
p = stpecat(stpecat(stpecat(buf, "Hello", past_end), " foo", past_end), "", past_end);- len = p - buf;
- if (p == past_end) {
- len--;
- puts("Following string is truncated.");
- }
- printf("%ti: %s\n", len, buf);
p = stpecat(stpecat(stpecat(buf, "Hello", past_end), " baar", past_end), "", past_end);- len = p - buf;
- if (p == past_end) {
- len--;
- puts("Following string is truncated.");
- }
- printf("%ti: %s\n", len, buf);
p = stpecat(stpecat(buf, "H", past_end), "W", past_end);- len = p - buf;
- if (p == past_end) {
- len--;
- puts("Following string is truncated.");
- }
- printf("%ti: %s\n", len, buf);
- }
- ```
- Which prints:
- ```c
- $ ./a.out
- Following string is truncated.
- 9: Hello wor
- 9: Hello foo
- Following string is truncated.
- 9: Hello baa
- 2: HW
- ```
- After addressing @Lundin 's suggestions:
- - Implemented in terms of libc functions for performance.
- - const correctness
- - style improvements
- I have one more that I realized after trying to replace some existing code:
- Much code out there has `char *end = buf + nitems(buf);` (although that should really be called `past_end`). That's certainly easier to calculate than the real `end` that I used here, since you don't need to stick that `-1` all around, and therefore has less chance of an accident.
- So, I tweaked it to have the following definition:
- ```c
- char *_Nonnull
- stpecpy(char *_Nonnull dst,
- const char *_Nonnull restrict src,
- char *_Nonnull past_end)
- {
- char *p;
- if (dst == past_end)
- return past_end;
- p = memccpy(dst, src, '\0', past_end - dst);
- if (p != NULL)
- return p - 1;
- /* truncation detected */
- past_end[-1] = '\0';
- return past_end;
- }
- ```
- To be clear, the return pointer is still the same: the pointer to the NUL byte on success, or one-past-the-array on truncation. It's only the last parameter that has changed to be a pointer one-past-the-array, which is simpler to get for users.
- The name of the function st**pe**cpy() seems to also have nice mnemonics for `past_end`.
- Now the use is slightly simpler:
- ```c
- int
- main(void)
- {
- ptrdiff_t size = 10;
- char buf[size];
- char *past_end, *p;
- ptrdiff_t len;
- past_end = &buf[size];
- p = stpecpy(stpecpy(buf, "Hello", past_end), " world", past_end);
- len = p - buf;
- if (p == past_end) {
- len--;
- puts("Following string is truncated.");
- }
- printf("%ti: %s\n", len, buf);
- p = stpecpy(stpecpy(stpecpy(buf, "Hello", past_end), " foo", past_end), "", past_end);
- len = p - buf;
- if (p == past_end) {
- len--;
- puts("Following string is truncated.");
- }
- printf("%ti: %s\n", len, buf);
- p = stpecpy(stpecpy(stpecpy(buf, "Hello", past_end), " baar", past_end), "", past_end);
- len = p - buf;
- if (p == past_end) {
- len--;
- puts("Following string is truncated.");
- }
- printf("%ti: %s\n", len, buf);
- p = stpecpy(stpecpy(buf, "H", past_end), "W", past_end);
- len = p - buf;
- if (p == past_end) {
- len--;
- puts("Following string is truncated.");
- }
- printf("%ti: %s\n", len, buf);
- }
- ```
- Which prints:
- ```c
- $ ./a.out
- Following string is truncated.
- 9: Hello wor
- 9: Hello foo
- Following string is truncated.
- 9: Hello baa
- 2: HW
- ```
#7: Post edited
- After addressing @Lundin 's suggestions:
- - Implemented in terms of libc functions for performance.
- - const correctness
- - style improvements
I have one that I realized after trying to replace some existing code:- Much code out there has `char *end = buf + nitems(buf);` (although that should really be called `past_end`). That's certainly easier to calculate than the real `end` that I used here, since you don't need to stick that `-1` all around, and therefore has less chance of an accident.
So, I tweaked `stpecpy()` to have the following definition:- ```c
- char *_Nonnull
stpecpy(char *_Nonnull dst,- const char *_Nonnull restrict src,
- char *_Nonnull past_end)
- {
- char *p;
- if (dst == past_end)
- return past_end;
- p = memccpy(dst, src, '\0', past_end - dst);
- if (p != NULL)
- return p - 1;
- /* truncation detected */
- past_end[-1] = '\0';
- return past_end;
- }
- ```
- To be clear, the return pointer is still the same: the pointer to the NUL byte on success, or one-past-the-array on truncation. It's only the last parameter that has changed to be a pointer one-past-the-array, which is simpler to get for users.
The name of the function st**pe**cpy() seems to also have nice mnemonics for `past_end`.- Now the use is slightly simpler:
- ```c
- int
- main(void)
- {
- ptrdiff_t size = 10;
- char buf[size];
- char *past_end, *p;
- ptrdiff_t len;
- past_end = &buf[size];
p = stpecpy(stpecpy(buf, "Hello", past_end), " world", past_end);- len = p - buf;
- if (p == past_end) {
- len--;
- puts("Following string is truncated.");
- }
- printf("%ti: %s\n", len, buf);
p = stpecpy(stpecpy(stpecpy(buf, "Hello", past_end), " foo", past_end), "", past_end);- len = p - buf;
- if (p == past_end) {
- len--;
- puts("Following string is truncated.");
- }
- printf("%ti: %s\n", len, buf);
p = stpecpy(stpecpy(stpecpy(buf, "Hello", past_end), " baar", past_end), "", past_end);- len = p - buf;
- if (p == past_end) {
- len--;
- puts("Following string is truncated.");
- }
- printf("%ti: %s\n", len, buf);
p = stpecpy(stpecpy(buf, "H", past_end), "W", past_end);- len = p - buf;
- if (p == past_end) {
- len--;
- puts("Following string is truncated.");
- }
- printf("%ti: %s\n", len, buf);
- }
- ```
- Which prints:
- ```c
- $ ./a.out
- Following string is truncated.
- 9: Hello wor
- 9: Hello foo
- Following string is truncated.
- 9: Hello baa
- 2: HW
- ```
- After addressing @Lundin 's suggestions:
- - Implemented in terms of libc functions for performance.
- - const correctness
- - style improvements
- I have a couple that I realized after trying to replace some existing code:
- Much code out there has `char *end = buf + nitems(buf);` (although that should really be called `past_end`). That's certainly easier to calculate than the real `end` that I used here, since you don't need to stick that `-1` all around, and therefore has less chance of an accident.
- And, strlcpy(3) is fine for copying; this function only improves the status quo for concatenating, so it's better to name it appropriately: `stpecat()`.
- So, I tweaked it to have the following definition:
- ```c
- char *_Nonnull
- stpecat(char *_Nonnull dst,
- const char *_Nonnull restrict src,
- char *_Nonnull past_end)
- {
- char *p;
- if (dst == past_end)
- return past_end;
- p = memccpy(dst, src, '\0', past_end - dst);
- if (p != NULL)
- return p - 1;
- /* truncation detected */
- past_end[-1] = '\0';
- return past_end;
- }
- ```
- To be clear, the return pointer is still the same: the pointer to the NUL byte on success, or one-past-the-array on truncation. It's only the last parameter that has changed to be a pointer one-past-the-array, which is simpler to get for users.
- The name of the function st**pe**cat() seems to also have nice mnemonics for `past_end`.
- Now the use is slightly simpler:
- ```c
- int
- main(void)
- {
- ptrdiff_t size = 10;
- char buf[size];
- char *past_end, *p;
- ptrdiff_t len;
- past_end = &buf[size];
- p = stpecat(stpecpy(buf, "Hello", past_end), " world", past_end);
- len = p - buf;
- if (p == past_end) {
- len--;
- puts("Following string is truncated.");
- }
- printf("%ti: %s\n", len, buf);
- p = stpecat(stpecat(stpecat(buf, "Hello", past_end), " foo", past_end), "", past_end);
- len = p - buf;
- if (p == past_end) {
- len--;
- puts("Following string is truncated.");
- }
- printf("%ti: %s\n", len, buf);
- p = stpecat(stpecat(stpecat(buf, "Hello", past_end), " baar", past_end), "", past_end);
- len = p - buf;
- if (p == past_end) {
- len--;
- puts("Following string is truncated.");
- }
- printf("%ti: %s\n", len, buf);
- p = stpecat(stpecat(buf, "H", past_end), "W", past_end);
- len = p - buf;
- if (p == past_end) {
- len--;
- puts("Following string is truncated.");
- }
- printf("%ti: %s\n", len, buf);
- }
- ```
- Which prints:
- ```c
- $ ./a.out
- Following string is truncated.
- 9: Hello wor
- 9: Hello foo
- Following string is truncated.
- 9: Hello baa
- 2: HW
- ```
#6: Post edited
- After addressing @Lundin 's suggestions:
- - Implemented in terms of libc functions for performance.
- - const correctness
- - style improvements
- I have one that I realized after trying to replace some existing code:
- Much code out there has `char *end = buf + nitems(buf);` (although that should really be called `past_end`). That's certainly easier to calculate than the real `end` that I used here, since you don't need to stick that `-1` all around, and therefore has less chance of an accident.
- So, I tweaked `stpecpy()` to have the following definition:
- ```c
- char *_Nonnull
- stpecpy(char *_Nonnull dst,
- const char *_Nonnull restrict src,
- char *_Nonnull past_end)
- {
- char *p;
- if (dst == past_end)
- return past_end;
- p = memccpy(dst, src, '\0', past_end - dst);
- if (p != NULL)
- return p - 1;
- /* truncation detected */
- past_end[-1] = '\0';
- return past_end;
- }
- ```
- To be clear, the return pointer is still the same: the pointer to the NUL byte on success, or one-past-the-array on truncation. It's only the last parameter that has changed to be a pointer one-past-the-array, which is simpler to get for users.
- The name of the function st**pe**cpy() seems to also have nice mnemonics for `past_end`.
- Now the use is slightly simpler:
- ```c
- int
- main(void)
- {
- ptrdiff_t size = 10;
- char buf[size];
- char *past_end, *p;
- ptrdiff_t len;
- past_end = &buf[size];
- p = stpecpy(stpecpy(buf, "Hello", past_end), " world", past_end);
- len = p - buf;
- if (p == past_end) {
- len--;
- puts("Following string is truncated.");
- }
- printf("%ti: %s\n", len, buf);
- p = stpecpy(stpecpy(stpecpy(buf, "Hello", past_end), " foo", past_end), "", past_end);
- len = p - buf;
- if (p == past_end) {
- len--;
- puts("Following string is truncated.");
- }
- printf("%ti: %s\n", len, buf);
- p = stpecpy(stpecpy(stpecpy(buf, "Hello", past_end), " baar", past_end), "", past_end);
- len = p - buf;
- if (p == past_end) {
- len--;
- puts("Following string is truncated.");
- }
- printf("%ti: %s\n", len, buf);
- p = stpecpy(stpecpy(buf, "H", past_end), "W", past_end);
- len = p - buf;
- if (p == past_end) {
- len--;
- puts("Following string is truncated.");
- }
- printf("%ti: %s\n", len, buf);
- }
- ```
- After addressing @Lundin 's suggestions:
- - Implemented in terms of libc functions for performance.
- - const correctness
- - style improvements
- I have one that I realized after trying to replace some existing code:
- Much code out there has `char *end = buf + nitems(buf);` (although that should really be called `past_end`). That's certainly easier to calculate than the real `end` that I used here, since you don't need to stick that `-1` all around, and therefore has less chance of an accident.
- So, I tweaked `stpecpy()` to have the following definition:
- ```c
- char *_Nonnull
- stpecpy(char *_Nonnull dst,
- const char *_Nonnull restrict src,
- char *_Nonnull past_end)
- {
- char *p;
- if (dst == past_end)
- return past_end;
- p = memccpy(dst, src, '\0', past_end - dst);
- if (p != NULL)
- return p - 1;
- /* truncation detected */
- past_end[-1] = '\0';
- return past_end;
- }
- ```
- To be clear, the return pointer is still the same: the pointer to the NUL byte on success, or one-past-the-array on truncation. It's only the last parameter that has changed to be a pointer one-past-the-array, which is simpler to get for users.
- The name of the function st**pe**cpy() seems to also have nice mnemonics for `past_end`.
- Now the use is slightly simpler:
- ```c
- int
- main(void)
- {
- ptrdiff_t size = 10;
- char buf[size];
- char *past_end, *p;
- ptrdiff_t len;
- past_end = &buf[size];
- p = stpecpy(stpecpy(buf, "Hello", past_end), " world", past_end);
- len = p - buf;
- if (p == past_end) {
- len--;
- puts("Following string is truncated.");
- }
- printf("%ti: %s\n", len, buf);
- p = stpecpy(stpecpy(stpecpy(buf, "Hello", past_end), " foo", past_end), "", past_end);
- len = p - buf;
- if (p == past_end) {
- len--;
- puts("Following string is truncated.");
- }
- printf("%ti: %s\n", len, buf);
- p = stpecpy(stpecpy(stpecpy(buf, "Hello", past_end), " baar", past_end), "", past_end);
- len = p - buf;
- if (p == past_end) {
- len--;
- puts("Following string is truncated.");
- }
- printf("%ti: %s\n", len, buf);
- p = stpecpy(stpecpy(buf, "H", past_end), "W", past_end);
- len = p - buf;
- if (p == past_end) {
- len--;
- puts("Following string is truncated.");
- }
- printf("%ti: %s\n", len, buf);
- }
- ```
- Which prints:
- ```c
- $ ./a.out
- Following string is truncated.
- 9: Hello wor
- 9: Hello foo
- Following string is truncated.
- 9: Hello baa
- 2: HW
- ```
#5: Post edited
- After addressing @Lundin 's suggestions:
- - Implemented in terms of libc functions for performance.
- - const correctness
- - style improvements
- I have one that I realized after trying to replace some existing code:
- Much code out there has `char *end = buf + nitems(buf);` (although that should really be called `past_end`). That's certainly easier to calculate than the real `end` that I used here, since you don't need to stick that `-1` all around, and therefore has less chance of an accident.
- So, I tweaked `stpecpy()` to have the following definition:
- ```c
- char *_Nonnull
- stpecpy(char *_Nonnull dst,
- const char *_Nonnull restrict src,
- char *_Nonnull past_end)
- {
- char *p;
- if (dst == past_end)
- return past_end;
- p = memccpy(dst, src, '\0', past_end - dst);
- if (p != NULL)
- return p - 1;
- /* truncation detected */
- past_end[-1] = '\0';
- return past_end;
- }
- ```
- To be clear, the return pointer is still the same: the pointer to the NUL byte on success, or one-past-the-array on truncation. It's only the last parameter that has changed to be a pointer one-past-the-array, which is simpler to get for users.
- The name of the function st**pe**cpy() seems to also have nice mnemonics for `past_end`.
- Now the use is slightly simpler:
- ```c
- int
- main(void)
- {
- ptrdiff_t size = 10;
- char buf[size];
- char *past_end, *p;
- ptrdiff_t len;
- past_end = &buf[size];
- p = stpecpy(stpecpy(buf, "Hello", past_end), " world", past_end);
- len = p - buf;
- if (p == past_end) {
- len--;
- puts("Following string is truncated.");
- }
- printf("%ti: %s\n", len, buf);
p = stpecpy(stpecpy(stpecpy(buf, "Hello", past_end), " foo", end), "", past_end);- len = p - buf;
- if (p == past_end) {
- len--;
- puts("Following string is truncated.");
- }
- printf("%ti: %s\n", len, buf);
p = stpecpy(stpecpy(stpecpy(buf, "Hello", past_end), " baar", end), "", past_end);- len = p - buf;
- if (p == past_end) {
- len--;
- puts("Following string is truncated.");
- }
- printf("%ti: %s\n", len, buf);
- p = stpecpy(stpecpy(buf, "H", past_end), "W", past_end);
- len = p - buf;
- if (p == past_end) {
- len--;
- puts("Following string is truncated.");
- }
- printf("%ti: %s\n", len, buf);
- }
- ```
- After addressing @Lundin 's suggestions:
- - Implemented in terms of libc functions for performance.
- - const correctness
- - style improvements
- I have one that I realized after trying to replace some existing code:
- Much code out there has `char *end = buf + nitems(buf);` (although that should really be called `past_end`). That's certainly easier to calculate than the real `end` that I used here, since you don't need to stick that `-1` all around, and therefore has less chance of an accident.
- So, I tweaked `stpecpy()` to have the following definition:
- ```c
- char *_Nonnull
- stpecpy(char *_Nonnull dst,
- const char *_Nonnull restrict src,
- char *_Nonnull past_end)
- {
- char *p;
- if (dst == past_end)
- return past_end;
- p = memccpy(dst, src, '\0', past_end - dst);
- if (p != NULL)
- return p - 1;
- /* truncation detected */
- past_end[-1] = '\0';
- return past_end;
- }
- ```
- To be clear, the return pointer is still the same: the pointer to the NUL byte on success, or one-past-the-array on truncation. It's only the last parameter that has changed to be a pointer one-past-the-array, which is simpler to get for users.
- The name of the function st**pe**cpy() seems to also have nice mnemonics for `past_end`.
- Now the use is slightly simpler:
- ```c
- int
- main(void)
- {
- ptrdiff_t size = 10;
- char buf[size];
- char *past_end, *p;
- ptrdiff_t len;
- past_end = &buf[size];
- p = stpecpy(stpecpy(buf, "Hello", past_end), " world", past_end);
- len = p - buf;
- if (p == past_end) {
- len--;
- puts("Following string is truncated.");
- }
- printf("%ti: %s\n", len, buf);
- p = stpecpy(stpecpy(stpecpy(buf, "Hello", past_end), " foo", past_end), "", past_end);
- len = p - buf;
- if (p == past_end) {
- len--;
- puts("Following string is truncated.");
- }
- printf("%ti: %s\n", len, buf);
- p = stpecpy(stpecpy(stpecpy(buf, "Hello", past_end), " baar", past_end), "", past_end);
- len = p - buf;
- if (p == past_end) {
- len--;
- puts("Following string is truncated.");
- }
- printf("%ti: %s\n", len, buf);
- p = stpecpy(stpecpy(buf, "H", past_end), "W", past_end);
- len = p - buf;
- if (p == past_end) {
- len--;
- puts("Following string is truncated.");
- }
- printf("%ti: %s\n", len, buf);
- }
- ```
#4: Post edited
- After addressing @Lundin 's suggestions:
- - Implemented in terms of libc functions for performance.
- - const correctness
- - style improvements
- I have one that I realized after trying to replace some existing code:
- Much code out there has `char *end = buf + nitems(buf);` (although that should really be called `past_end`). That's certainly easier to calculate than the real `end` that I used here, since you don't need to stick that `-1` all around, and therefore has less chance of an accident.
- So, I tweaked `stpecpy()` to have the following definition:
- ```c
- char *_Nonnull
- stpecpy(char *_Nonnull dst,
- const char *_Nonnull restrict src,
- char *_Nonnull past_end)
- {
- char *p;
- if (dst == past_end)
- return past_end;
- p = memccpy(dst, src, '\0', past_end - dst);
- if (p != NULL)
- return p - 1;
- /* truncation detected */
- past_end[-1] = '\0';
- return past_end;
- }
- ```
To be clear, the return pointer is still the same: the pointer to the NUL byte. It's only the last parameter that has changed to be a pointer one-past-the-array, which is nicer as a sentinel.- The name of the function st**pe**cpy() seems to also have nice mnemonics for `past_end`.
- Now the use is slightly simpler:
- ```c
- int
- main(void)
- {
- ptrdiff_t size = 10;
- char buf[size];
- char *past_end, *p;
- ptrdiff_t len;
- past_end = &buf[size];
- p = stpecpy(stpecpy(buf, "Hello", past_end), " world", past_end);
- len = p - buf;
- if (p == past_end) {
- len--;
- puts("Following string is truncated.");
- }
- printf("%ti: %s\n", len, buf);
- p = stpecpy(stpecpy(stpecpy(buf, "Hello", past_end), " foo", end), "", past_end);
- len = p - buf;
- if (p == past_end) {
- len--;
- puts("Following string is truncated.");
- }
- printf("%ti: %s\n", len, buf);
- p = stpecpy(stpecpy(stpecpy(buf, "Hello", past_end), " baar", end), "", past_end);
- len = p - buf;
- if (p == past_end) {
- len--;
- puts("Following string is truncated.");
- }
- printf("%ti: %s\n", len, buf);
- p = stpecpy(stpecpy(buf, "H", past_end), "W", past_end);
- len = p - buf;
- if (p == past_end) {
- len--;
- puts("Following string is truncated.");
- }
- printf("%ti: %s\n", len, buf);
- }
- ```
- After addressing @Lundin 's suggestions:
- - Implemented in terms of libc functions for performance.
- - const correctness
- - style improvements
- I have one that I realized after trying to replace some existing code:
- Much code out there has `char *end = buf + nitems(buf);` (although that should really be called `past_end`). That's certainly easier to calculate than the real `end` that I used here, since you don't need to stick that `-1` all around, and therefore has less chance of an accident.
- So, I tweaked `stpecpy()` to have the following definition:
- ```c
- char *_Nonnull
- stpecpy(char *_Nonnull dst,
- const char *_Nonnull restrict src,
- char *_Nonnull past_end)
- {
- char *p;
- if (dst == past_end)
- return past_end;
- p = memccpy(dst, src, '\0', past_end - dst);
- if (p != NULL)
- return p - 1;
- /* truncation detected */
- past_end[-1] = '\0';
- return past_end;
- }
- ```
- To be clear, the return pointer is still the same: the pointer to the NUL byte on success, or one-past-the-array on truncation. It's only the last parameter that has changed to be a pointer one-past-the-array, which is simpler to get for users.
- The name of the function st**pe**cpy() seems to also have nice mnemonics for `past_end`.
- Now the use is slightly simpler:
- ```c
- int
- main(void)
- {
- ptrdiff_t size = 10;
- char buf[size];
- char *past_end, *p;
- ptrdiff_t len;
- past_end = &buf[size];
- p = stpecpy(stpecpy(buf, "Hello", past_end), " world", past_end);
- len = p - buf;
- if (p == past_end) {
- len--;
- puts("Following string is truncated.");
- }
- printf("%ti: %s\n", len, buf);
- p = stpecpy(stpecpy(stpecpy(buf, "Hello", past_end), " foo", end), "", past_end);
- len = p - buf;
- if (p == past_end) {
- len--;
- puts("Following string is truncated.");
- }
- printf("%ti: %s\n", len, buf);
- p = stpecpy(stpecpy(stpecpy(buf, "Hello", past_end), " baar", end), "", past_end);
- len = p - buf;
- if (p == past_end) {
- len--;
- puts("Following string is truncated.");
- }
- printf("%ti: %s\n", len, buf);
- p = stpecpy(stpecpy(buf, "H", past_end), "W", past_end);
- len = p - buf;
- if (p == past_end) {
- len--;
- puts("Following string is truncated.");
- }
- printf("%ti: %s\n", len, buf);
- }
- ```
#3: Post edited
- After addressing @Lundin 's suggestions:
- - Implemented in terms of libc functions for performance.
- - const correctness
- - style improvements
- I have one that I realized after trying to replace some existing code:
- Much code out there has `char *end = buf + nitems(buf);` (although that should really be called `past_end`). That's certainly easier to calculate than the real `end` that I used here, since you don't need to stick that `-1` all around, and therefore has less chance of an accident.
- So, I tweaked `stpecpy()` to have the following definition:
- ```c
- char *_Nonnull
- stpecpy(char *_Nonnull dst,
- const char *_Nonnull restrict src,
- char *_Nonnull past_end)
- {
- char *p;
- if (dst == past_end)
- return past_end;
- p = memccpy(dst, src, '\0', past_end - dst);
- if (p != NULL)
- return p - 1;
- /* truncation detected */
- past_end[-1] = '\0';
- return past_end;
- }
- ```
- The name of the function st**pe**cpy() seems to also have nice mnemonics for `past_end`.
- Now the use is slightly simpler:
- ```c
- int
- main(void)
- {
- ptrdiff_t size = 10;
- char buf[size];
- char *past_end, *p;
- ptrdiff_t len;
- past_end = &buf[size];
- p = stpecpy(stpecpy(buf, "Hello", past_end), " world", past_end);
- len = p - buf;
- if (p == past_end) {
- len--;
- puts("Following string is truncated.");
- }
- printf("%ti: %s\n", len, buf);
- p = stpecpy(stpecpy(stpecpy(buf, "Hello", past_end), " foo", end), "", past_end);
- len = p - buf;
- if (p == past_end) {
- len--;
- puts("Following string is truncated.");
- }
- printf("%ti: %s\n", len, buf);
- p = stpecpy(stpecpy(stpecpy(buf, "Hello", past_end), " baar", end), "", past_end);
- len = p - buf;
- if (p == past_end) {
- len--;
- puts("Following string is truncated.");
- }
- printf("%ti: %s\n", len, buf);
- p = stpecpy(stpecpy(buf, "H", past_end), "W", past_end);
- len = p - buf;
- if (p == past_end) {
- len--;
- puts("Following string is truncated.");
- }
- printf("%ti: %s\n", len, buf);
- }
- ```
- After addressing @Lundin 's suggestions:
- - Implemented in terms of libc functions for performance.
- - const correctness
- - style improvements
- I have one that I realized after trying to replace some existing code:
- Much code out there has `char *end = buf + nitems(buf);` (although that should really be called `past_end`). That's certainly easier to calculate than the real `end` that I used here, since you don't need to stick that `-1` all around, and therefore has less chance of an accident.
- So, I tweaked `stpecpy()` to have the following definition:
- ```c
- char *_Nonnull
- stpecpy(char *_Nonnull dst,
- const char *_Nonnull restrict src,
- char *_Nonnull past_end)
- {
- char *p;
- if (dst == past_end)
- return past_end;
- p = memccpy(dst, src, '\0', past_end - dst);
- if (p != NULL)
- return p - 1;
- /* truncation detected */
- past_end[-1] = '\0';
- return past_end;
- }
- ```
- To be clear, the return pointer is still the same: the pointer to the NUL byte. It's only the last parameter that has changed to be a pointer one-past-the-array, which is nicer as a sentinel.
- The name of the function st**pe**cpy() seems to also have nice mnemonics for `past_end`.
- Now the use is slightly simpler:
- ```c
- int
- main(void)
- {
- ptrdiff_t size = 10;
- char buf[size];
- char *past_end, *p;
- ptrdiff_t len;
- past_end = &buf[size];
- p = stpecpy(stpecpy(buf, "Hello", past_end), " world", past_end);
- len = p - buf;
- if (p == past_end) {
- len--;
- puts("Following string is truncated.");
- }
- printf("%ti: %s\n", len, buf);
- p = stpecpy(stpecpy(stpecpy(buf, "Hello", past_end), " foo", end), "", past_end);
- len = p - buf;
- if (p == past_end) {
- len--;
- puts("Following string is truncated.");
- }
- printf("%ti: %s\n", len, buf);
- p = stpecpy(stpecpy(stpecpy(buf, "Hello", past_end), " baar", end), "", past_end);
- len = p - buf;
- if (p == past_end) {
- len--;
- puts("Following string is truncated.");
- }
- printf("%ti: %s\n", len, buf);
- p = stpecpy(stpecpy(buf, "H", past_end), "W", past_end);
- len = p - buf;
- if (p == past_end) {
- len--;
- puts("Following string is truncated.");
- }
- printf("%ti: %s\n", len, buf);
- }
- ```
#2: Post edited
- After addressing @Lundin 's suggestions:
- - Implemented in terms of libc functions for performance.
- - const correctness
- - style improvements
- I have one that I realized after trying to replace some existing code:
- Much code out there has `char *end = buf + nitems(buf);` (although that should really be called `past_end`). That's certainly easier to calculate than the real `end` that I used here, since you don't need to stick that `-1` all around, and therefore has less chance of an accident.
- So, I tweaked `stpecpy()` to have the following definition:
- ```c
- char *_Nonnull
- stpecpy(char *_Nonnull dst,
- const char *_Nonnull restrict src,
- char *_Nonnull past_end)
- {
- char *p;
- if (dst == past_end)
- return past_end;
- p = memccpy(dst, src, '\0', past_end - dst);
- if (p != NULL)
- return p - 1;
- /* truncation detected */
- past_end[-1] = '\0';
- return past_end;
- }
- ```
- The name of the function st**pe**cpy() seems to also have nice mnemonics for `past_end`.
- Now the use is slightly simpler:
- ```c
- int
- main(void)
- {
- ptrdiff_t size = 10;
- char buf[size];
char *past_end;- ptrdiff_t len;
- past_end = &buf[size];
len = stpecpy(stpecpy(buf, "Hello", past_end), " world", past_end) - buf;if (len == size) {- len--;
- puts("Following string is truncated.");
- }
- printf("%ti: %s\n", len, buf);
len = stpecpy(stpecpy(stpecpy(buf, "Hello", past_end), " foo", end), "", past_end) - buf;if (len == size) {- len--;
- puts("Following string is truncated.");
- }
- printf("%ti: %s\n", len, buf);
len = stpecpy(stpecpy(stpecpy(buf, "Hello", past_end), " baar", end), "", past_end) - buf;if (len == size) {- len--;
- puts("Following string is truncated.");
- }
- printf("%ti: %s\n", len, buf);
len = stpecpy(stpecpy(buf, "H", past_end), "W", past_end) - buf;if (len == size) {- len--;
- puts("Following string is truncated.");
- }
- printf("%ti: %s\n", len, buf);
- }
- ```
- After addressing @Lundin 's suggestions:
- - Implemented in terms of libc functions for performance.
- - const correctness
- - style improvements
- I have one that I realized after trying to replace some existing code:
- Much code out there has `char *end = buf + nitems(buf);` (although that should really be called `past_end`). That's certainly easier to calculate than the real `end` that I used here, since you don't need to stick that `-1` all around, and therefore has less chance of an accident.
- So, I tweaked `stpecpy()` to have the following definition:
- ```c
- char *_Nonnull
- stpecpy(char *_Nonnull dst,
- const char *_Nonnull restrict src,
- char *_Nonnull past_end)
- {
- char *p;
- if (dst == past_end)
- return past_end;
- p = memccpy(dst, src, '\0', past_end - dst);
- if (p != NULL)
- return p - 1;
- /* truncation detected */
- past_end[-1] = '\0';
- return past_end;
- }
- ```
- The name of the function st**pe**cpy() seems to also have nice mnemonics for `past_end`.
- Now the use is slightly simpler:
- ```c
- int
- main(void)
- {
- ptrdiff_t size = 10;
- char buf[size];
- char *past_end, *p;
- ptrdiff_t len;
- past_end = &buf[size];
- p = stpecpy(stpecpy(buf, "Hello", past_end), " world", past_end);
- len = p - buf;
- if (p == past_end) {
- len--;
- puts("Following string is truncated.");
- }
- printf("%ti: %s\n", len, buf);
- p = stpecpy(stpecpy(stpecpy(buf, "Hello", past_end), " foo", end), "", past_end);
- len = p - buf;
- if (p == past_end) {
- len--;
- puts("Following string is truncated.");
- }
- printf("%ti: %s\n", len, buf);
- p = stpecpy(stpecpy(stpecpy(buf, "Hello", past_end), " baar", end), "", past_end);
- len = p - buf;
- if (p == past_end) {
- len--;
- puts("Following string is truncated.");
- }
- printf("%ti: %s\n", len, buf);
- p = stpecpy(stpecpy(buf, "H", past_end), "W", past_end);
- len = p - buf;
- if (p == past_end) {
- len--;
- puts("Following string is truncated.");
- }
- printf("%ti: %s\n", len, buf);
- }
- ```
#1: Initial revision
After addressing @Lundin 's suggestions: - Implemented in terms of libc functions for performance. - const correctness - style improvements I have one that I realized after trying to replace some existing code: Much code out there has `char *end = buf + nitems(buf);` (although that should really be called `past_end`). That's certainly easier to calculate than the real `end` that I used here, since you don't need to stick that `-1` all around, and therefore has less chance of an accident. So, I tweaked `stpecpy()` to have the following definition: ```c char *_Nonnull stpecpy(char *_Nonnull dst, const char *_Nonnull restrict src, char *_Nonnull past_end) { char *p; if (dst == past_end) return past_end; p = memccpy(dst, src, '\0', past_end - dst); if (p != NULL) return p - 1; /* truncation detected */ past_end[-1] = '\0'; return past_end; } ``` The name of the function st**pe**cpy() seems to also have nice mnemonics for `past_end`. Now the use is slightly simpler: ```c int main(void) { ptrdiff_t size = 10; char buf[size]; char *past_end; ptrdiff_t len; past_end = &buf[size]; len = stpecpy(stpecpy(buf, "Hello", past_end), " world", past_end) - buf; if (len == size) { len--; puts("Following string is truncated."); } printf("%ti: %s\n", len, buf); len = stpecpy(stpecpy(stpecpy(buf, "Hello", past_end), " foo", end), "", past_end) - buf; if (len == size) { len--; puts("Following string is truncated."); } printf("%ti: %s\n", len, buf); len = stpecpy(stpecpy(stpecpy(buf, "Hello", past_end), " baar", end), "", past_end) - buf; if (len == size) { len--; puts("Following string is truncated."); } printf("%ti: %s\n", len, buf); len = stpecpy(stpecpy(buf, "H", past_end), "W", past_end) - buf; if (len == size) { len--; puts("Following string is truncated."); } printf("%ti: %s\n", len, buf); } ```