3 ms·
If you ever find yourself writing strcpy() followed by strcat(), consider: snprintf(buf, sizeof(buf), "%s%s", a, b); This as safe as strlcpy and strlcat, bu
by TazeTSchnitzel 3y ago
If you ever find yourself writing strcpy() followed by strcat(), consider:
snprintf(buf, sizeof(buf), "%s%s", a, b);
This as safe as strlcpy and strlcat, but more efficient, and has been standard for 24 years.
- saagarjha 3y ago1. This returns an int. 2. This is inefficient in a similar way that strlcpy is: it does more work than the size of the buffer.
- jstimpfle 3y ago1. This is only slightly less irrelevant than "this returns a size_t" if that were so. 2. You have the option to provide the length, snprintf(buf, sizeof buf, "%.*s%.*s", len1, str1, len2, str2); If you're bottlenecked by snprintf (hint: you aren't) then snprintf isn't your API anyway. Write some more custom code, probably some memcpy's etc.
- saagarjha 3y agoFor 1: returning an int means that you get some unspecified behavior on overflow. For 2 then you need to call strlen yourself which kind of defeats the point of using snprintf because you can just use memcpy instead.
- jstimpfle 3y agoFor 2: No you don't? There is no reason to fault snprintf() if you didn't already know the length of the string. And when you do know the lengths, no, there absolutely is a reason to use snprintf -- convenience. snprintf(buf, sizeof buf, "%s/%s", dirpath, filename); is much easier to write than an equivalent sequence of manual copies with temporary index variables and pointer arithmetic. Same for snprintf(buf, sizeof buf, "%.*s/%.*s", dirlen, dirpath, filelen, filename); if you really cared about squeezing the last drop from the API. For 1: Then don't overflow. It's not practical to process strings that big to allow a 32-bit overflow (or 16-bit overflow, on a 16-bit system), so it's unlikely anybody here has ever been in that situation anyway. Apart from that I'm not so sure that the API is specified to allow overflow to happen. It's probably an under-specified area of the contract, but I would first check that the result couldn't be -1 for example. Apart from that, what would be the reasonable specification in case of size_t overflow that would result in a controllable situation? Sometimes I think, C being probably better formalized than any other language is also a big reason for it being criticized so much. Language nerds just love to take the specs and try to shred it on theoretic grounds without any consideration of the practical.
- saagarjha 3y agoI open files that are larger than 4 GB from time to time, it’s not really reasonable to say that 32-bit is large enough for these kinds of things anymore. Well, let me rephrase: sometimes it’s ok to be “ok I don’t handle more than 4 billion (say this is a field to enter your name)” but there should also be a way to do it if I care enough, like when I’m writing a text editor. FWIW I believe most implementations will do something safe on overflow like terminate the program or return some error (can printf signal via errno?)
- orwin 3y agoHonestly just use memcopy and define your own string structure. C has void*, that allows you to implement easily modifiable data structures. There is a bit of 'NIH' syndrome in what I'm saying, I'll admit, but in the end it's better imho.
- jstimpfle 3y agoC is all about memory management and copying data around, and people can't stop whining that there is no magic string handling sauce (as if strings were special), and keep acting like we had to put up with the ridiculous strcat() etc. nonsense.
- jacquesm 3y agoThat's not what 'void*' is for.
- orwin 3y agoThat's how I use it though. As a data-agnostic type, so I can put whatever I like in my btrees/buffers/linked lists. I don't use it for string management, I guess reading my post again, I expressed myself poorly, again.
- loeg 3y agoBe careful, this does not work if buf is 'char*' rather than an array type.
- rwmj 3y agoasprintf is even better (although different because it allocates a new string).