3 ms·
>Did I mess up the code? You certainly did; both your benchmark functions overflow their internal buffers. However, it's not all that improbable for memccpy t
by eMSF 7y ago
>Did I mess up the code?
You certainly did; both your benchmark functions overflow their internal buffers.
However, it's not all that improbable for memccpy to be slower than strcpy in this case, even if it was used correctly; after all, it does more, and by doing so would prevent the buffer overflow if supplied with correct arguments (specifically, the last one). As to how much slower, I cannot tell. Also, you're skipping over half the point of the article by using a (fixed) source string, the size of which is known in advance.
In general, I would not benchmark library functions on local variables (buffers) without observing their results. It's far too easy for the compiler to remove the call altogether when said removal doesn't make any difference on the output.
- deleted 7y ago[deleted]
- johnisgood 7y ago> You're skipping over half the point of the article by using a (fixed) source string, the size of which is known in advance. You are right. I should have focused more on that instead, that seems more relevant to why the author of the article is suggesting memccpy. I am curious as to whether or not it really is the case that memccpy is "optimally efficient" in practice over the alternatives. Would you like to prove or disprove that statement yourself? I modified the code a bit; it uses strlen to calculate the length of the string passed, and the string is argv[1]. memccpy is still just as slow. Is this a more acceptable approach to you? In this case we do not know neither the string, nor its length in advance. strcpy still outperforms memccpy. Is this sufficient to disprove the claim that memccpy is "optimally" efficient to other alternatives? The other criterion was being widely adopted, in which case, well, strcpy also looks good. Moreover, as dwheeler pointed out, memccpy is a tad difficult to use in practice. I will give strlcpy a try, too, since I prefer that over strcpy. In any case, I am not convinced that these criteria hold true for memccpy over the alternatives. > on local variables (buffers) without observing their results What do you mean exactly? I did observe the results of the buffer. See the printf, or are you not referring to that? > both your benchmark functions overflow their internal buffers. Would you please elaborate on it, and its relevance? Are you referring to N being too high?
- johnisgood 7y agoAs far as stack overflow goes, you could just increase the stack size or make the N smaller. That is besides the point, I intentionally avoided dynamic memory allocation. Also even if I put everything (including the strlen) inside the loop, memccpy is still much slower. I still have not examined the assembler code.
- eMSF 7y ago>Would you please elaborate on it, and its relevance? Are you referring to N being too high? No, the stack size is implementation-defined anyway. Instead, you have a classic off-by-one error because you didn't reserve any space for the final null terminator. Correctly used memccpy would protect against an issue like this, although the destination string would not be correctly terminated, as it's not a safe string function. Also, if your memccpy version had the correct arguments inside the loop, you wouldn't have needed the extra call before the loop to hide the issue, as the memccpy call would have been functionally identical to strcpy except for the last pass of the loop. >What do you mean exactly? I did observe the results of the buffer. See the printf, or are you not referring to that? At least in the link you provided, all the printf's that would observe the contents of buf after the loop are commented out. No observable change happens in the execution of the program even if your compiler decides to just remove any calls to strcpy or memccpy. -- That being said, strcpy is quite efficient at what you're benchmarking; that is, "multiplying" short strings. The task doesn't highlight its shortcomings. (strcpy wouldn't be too bad even if the strings were longer, although memcpy might be slightly faster.) But consider the following silly example (not checked for errors) that does highlight the issue: char *next_insert; size_t remaining_size; void append_memccpy(const char *str) { char *tmp = memccpy(next_insert, str, '\0', remaining_size); // single pass over str if (tmp) { --tmp; // move pointer to terminator from one past it remaining_size -= tmp - next_insert; next_insert = tmp; } else { // insufficient size remaining str += remaining_size; // first remaining_size bytes are already copied allocate_more(); append_memccpy(str); } } void append_strcpy(const char *str) { size_t len = strlen(str); // first pass over str if (len + 1 < remaining_size) { strcpy(next_insert, str); // second pass over str remaining_size -= len; next_insert += len; } else { allocate_more(); append_strcpy(str); } } Now, even though the latter version is extra silly (just to resemble the former more), it doesn't change the fact that with strcpy, we have to process each byte in str twice. If str is long enough, that might not be exactly free.