3 ms·
> I've always felt that the standard library is a half-baked hodgepodge of inconsistencies It is! > Why is open() in fcntl.h and close() in unistd.h? Because
by jstimpfle 8y ago
> I've always felt that the standard library is a half-baked hodgepodge of inconsistencies
It is!
> Why is open() in fcntl.h and close() in unistd.h?
Because they don't belong together. open() is used to create an FD using a filesystem path. There are other ways to create FDs, like socket(). close() is used to close any FD. You could say open() has an unfortunate name. Neither open() nor close() are part of the C standard library, though. The standard library has the fopen() and fclose() functions, both defined in stdio.h. (And it's the same situation there: There are other ways to create a FILE than using fopen(), while fclose() can close any FILE (although fopen() is probably the only way defined in the standard library)).
> Why did they make strlcpy return a different value than strncpy
My advice is to just write your own string data structures and functions. Make the interface that you need. It's often bad to use C strings, anyway (they don't have an explicit length).
> But I don't know how anyone would find out about, say, strtok or strsep without encountering them in some existing code.
Man pages cross-reference similar functions. And there are index-manpages. For example, strcpy(3) references string(3) which lists all the functionality from string.h, including strtok(3).
> I had a university assignment which would have been trivial if anyone in the class knew that fts.h existed.
Never knew that one either. Not part of the C standard library I guess. Also, just write your own code. In my opinion the standard library is mainly useful for portable access to basic OS services.
- beefhash 8y ago> > I had a university assignment which would have been trivial if anyone in the class knew that fts.h existed. > Never knew that one either. Not part of the C standard library I guess. fts(3) is a BSD interface. It got introduced in 4.3BSD-Reno.
- rgovostes 8y ago> My advice is to just write your own string data structures and functions. I would rather not have to do this, and I would prefer code that I'm reviewing not do it either. C strings are error-prone, as you point out, and when I'm evaluating code for security issues, it's useful to know exactly how a function will behave in edge cases--is the buffer guaranteed to be terminated? is the return value the number of bytes written, like sprintf, or the number of bytes that could have been written, like snprintf? A new function with new behavior is twice the work: you have to verify it is consistent with the rules it claims to follow, and then make sure it is being used correctly. One memorable example was a convoluted routine that I suspected was the same as strdup() but I had to spend a while validating it. It's just a shame that so many of the standard library string functions fall short. This is the reason why there are so many security vulnerabilities, because there are too many nuances and inconsistencies. They messed up strcpy() so they introduced strncpy(), but they messed that up too so we had to create strlcpy(), which is not a drop-in replacement (and not portable apparently). So we've got 3 poor design choices implementing one trivial function, no clear replacement to reach for, and we expect every programmer to know this.
- jstimpfle 8y ago> is the return value the number of bytes written, like sprintf, or the number of bytes that could have been written, like snprintf? Both report the same number. snprintf just doesn't write more than n bytes. > when I'm evaluating code for security issues, it's useful to know exactly how a function will behave in edge cases simple data: no edge cases. Pointer + length, that's simple. The most complexity you might be facing is if you allow a NULL pointer in case of 0 length (which is common). There should be hardly any function that cares for that. Aside, C strings are still a valid alternate representation in some cases. For example, for many small strings (where an explicit length field would double the cost) or purely as a convenience in conjunction with string literals. Or for some serialized representations (it's nice not having to deal with compatibility problems concerning the physical representation of the length value). > This is the reason why there are so many security vulnerabilities, because there are too many nuances and inconsistencies. I think the reason is that the standard library is overused. Functions like strcat etc. are not only inefficient. They have a needlessly complex API. Would people create the functionality they actually needed instead of working around the ill-fitting API in each line of code, then there would be fewer vulnerabilities. > strcpy() [..] strncpy() [..] strlcpy [..] no clear replacement to reach for, and we expect every programmer to know this. No. Just don't use this stuff. It's too complex. It's the wrong interface. If you deal with strings and don't do automatic reallocation you need to get their lengths anyway. So what you should do is something like void do_silly_stuff(const char *a, const char *b, const char *c, int alen, int blen, int clen) { char buf[FIXEDSIZE]; ASSERT(alen + blen + clen <= sizeof buf); int len = 0; memcpy(buf + len, a, alen); len += alen; memcpy(buf + len, b, blen); len += blen; memcpy(buf + len, c, clen); len += clen; do_more_silly_stuff(buf, len); } Nice and explicit. You cannot get less dangerous in C. Or if you do automatic realloction ("dynamic string"): String sillyconcat(String a, String b, String c) { String result = new_string(); //optionally: // string_reserve(string_length(a) + string_length(b) + string_length(c)); string_append(result, a); string_append(result, b); string_append(result, c); return result; } ... but I'd only recommend this approach if you want to get super-comfortable and are willing to pay the cost of being maybe a bit opaque and of buying in into a specific String type.