What If I Don't Actually Like My Users? (2008)
ozlabs.org
ozlabs.org
This was to get a message out of the API. At the point one is making the call, it does know how long the message is. (Having already gotten a callback.) It looks like the author forgot to write the function that would return the length, then improvised.
Furthermore, the API probably doesn't want to allocate and buffer the data itself since it could be very long, nor does it want to impose a fixed limit since the application should decide that.
This was probably the case.
https://msdn.microsoft.com/en-us/library/windows/desktop/aa3...
... but the corresponding POSIX one doesn't:
http://pubs.opengroup.org/onlinepubs/009695399/functions/get...
http://insanecoding.blogspot.ca/2007/11/pathmax-simply-isnt....
Not fixed is that the ISO C wide character version of the function (swprintf) specifies a gratuitously different return value convention from from that of snprintf.
They should print that into every mirror manufactured.
// ... Function strcmp() returns 0 on match, therefore, !strcmp() is TRUE on match.
I deliberated with my inner voice for a minute on whether to include a comment or not. Ended up including the above thinking 18 !strcmp() statements looked strangely illogical in context even after just writing it.This better reinforces my mental model of it (like many comparison functions) having 3 possible return values: <0, =0, or >0. !strcmp(...) may be terser, but it is illogical in that logical not isn't an operator. I dig using it on booleans, or "booleanish" values (null vs non-null pointers), but this conceptual tri-state isn't even "booleanish". But C didn't have a proper bool type for awhile, and C++ inherited it's baggage, so they'll compile it.
Meanwhile C# doesn't even think my "booleanish" tests are logical enough to allow to compile - no null reference tests with "operator!" for me.
char * gets(char * s) ?
But for all of those functions, glibc and some other C libraries provide reentrant variants like "basename_r" and "ptsname_r".
For example, https://en.m.wikipedia.org/wiki/Write_(system_call)#POSIX_us... warns "The write function returns the number of bytes successfully written into the array, which may at times be less than the specified nbytes"
Yet, the example following it (https://en.m.wikipedia.org/wiki/Write_(system_call)#Usage_Ex...) doesn't handle that case or error codes such as EINTR.
I remember reading a text describing how to properly use that call, but cannot find it anymore. Faulty examples like the one above are easy to find, though. For example, http://stackoverflow.com/questions/14417806/are-posix-read-a... and http://stackoverflow.com/questions/10650861/atomicity-of-wri... are good questions, but no answer points out that, even if write were atomic, it would not do you any good, as you may have to call it multiple times.
It probably is not that difficult, but I think it would take me a day to wrap this function in something that doesn't explode in your face, and be confident that I did it correctly, and even then, I would wake up in bed wondering whether I handled all edge cases correctly.
safe_rw() http://git.savannah.gnu.org/gitweb/?p=gnulib.git;a=blob;f=li...
This handles a single read/write, handles EINTER, and returns the amount that was successfully read/written.
full_rw() http://git.savannah.gnu.org/gitweb/?p=gnulib.git;a=blob;f=li...
A wrapper around safe_rw() that handles advancing the pointer through the buffer, calling safe_rw() until the requested COUNT bytes have been sent/received.
--
In most cases, I recommend avoiding all of this and using the existing fopen/fread/fwrite/etc buffered I/O interface.
The f() calls all buffer for you.
The problem is that write() is entangled in the ioctl() universe in many implementations of 'C' and that gets funky fast.
Beyond* that, reading and writing may involve making your own furniture to hide the ugly from dealing with peripherals.
I heard this idea was toyed with by the ISO C committee. Evidently, D. Gwyn proposed BUFSIZ to be re-used for this purpose.
Current versions of glibc actually mark gets as deprecated (so you'll get a warning if you use it), and don't provide it at all if building for C11 or newer.
Since I don't use gets, I have to imagine myself fixing some legacy code.
Firstly, I imagine that this code already defines the arrays, so all I have to do is edit the definition to use this use this fictitious GETS_MAX constant, for which I have to include one simple header (which might already be included for something else). No actual logic has changed. (On the other hand, the adjustment to the size of the array to GETS_MAX could be a problematic issue; it is not without risk of something breaking.)
To use fgets, I have to edit the calls to add the size parameter. Moreover, I have to scan the buffer for the presence of a newline character and overwrite it with a null. gets does that and the code may be relying on it (using "relying" ironically, with regard to gets).
> bind() socket library call ... takes a struct sockaddr [when you are usually using a struct sockaddr_in]
Except the compiler is correct. If you want to use a polymorphic type in a generic call that requires the parent type, you should include a cast.
From the example in my man page for bind(2):
int main(int argc, char *argv[])
{
int sfd;
struct sockaddr_un my_addr;
/* ... */
if (bind(sfd, (struct sockaddr *) &my_addr,
sizeof(struct sockaddr_un)) == -1)
handle_error("bind");
/* ,,, */This felt completely intuitive to me the first time I saw it: a comparison of characters can result in "less", "greater", or "equal" much like a subtraction would, and if this is expressed as an integer, < 0, > 0, and == 0 are a very sensible set of possible alternatives, and of those the only one that makes most sense as "equality" is the == 0, which is idiomatically expressed as !. I think if(strcmp(...)), if(!strcmp(...)), and ditto for memcmp() and related "3-value" comparison idioms might be one of those things that divide programmers into two groups: one that instantly sees the elegance of this design and thinks it's so natural and obvious, and one that gets eternally confused by it.
That is why I always write == 0 on comparison even if it is longer. It removes a negative and makes it clear.
If it helps, you should think of strcmp() as returning a difference. strcmp() means "string comparison", and to compare is to find differences. Thus the "not" means "no difference", just as the idiom "if(!p)" means "there is no (object pointed to by) p".
That is why I always write == 0 on comparison even if it is longer. It removes a negative and makes it clear.
Seeing "== 0" for that in C for me is actually like seeing the equivalent of "== false" in languages that have booleans: the extra comparison causes a bit of pondering at whether it was really what the programmer intended. The if(...) is already an implicit comparison with 0/nonzero. I've seen things like this too, presumably written by someone who wanted to make the comparison really explicit, but just ends up causing more confusion IMHO:
if ((strcmp(a, b) == 0) != false) {
/* does this code get executed when the strings are equal or different? */
}> "not" means "no difference
I'd rather see less "not"s, it is easier to reason about. "not" means logical expressions to me, strcmp returns numbers, I would rather keep ! away.
> "if(!p)" means "there is no (object pointed to by) p".
Ok, now we have pointer in play. strcmp really does return numbers. Why bring pointers or logic operators, doesn't that confuse things? It does for me.
> ((strcmp(a, b) == 0) != false)
I have never seen that. And would never advocate for that, why are we doing it that way again?
>I have never seen that. And would never advocate for that, why are we doing it that way again?
I think a more reasonable example would be (with some reasonably namespaced define, blah blah blah):
strcmp(a, b) == CMP_EQUAL;What happens when people actually do start using !strcmp() and then add an additional != false anyway?
Your example doesn't show that it's hard to understand what ==0 means, it shows that some people don't understand booleans, which is no less true of your method than the other.
strcmp is a comparison. Comparisons are intuitively boolean unless there's a clear reason to be otherwise, and "false=0, true=nonzero" is well-known. Therefore, "strcmp('foo', 'foo')" shouldn't return 0 any more than "5 == 5" should return 0.
If the function were called "strsub" or "strdiff" and was described as taking the difference of two strings, then this might be an elegant solution, but "comparison" means something specific in a programming context, and this isn't it.
(I keed, I keed )
Are comparisons in general boolean? I think specific operators are, but that's because they are asking a particular boolean question. A general "compare X and Y" doesn't seem like it should ever be "true" or "false" (because what would those mean? Different --- in what way, less, greater, or both --- or equal?)
As the sibling comment alludes to, comparisons are really a form of subtraction to the hardware, and C makes this fact very obvious.
In assembler, comparisons generally have a result of zero when things are the same because hardware works that way. If the difference between two voltages is zero, they "null" and are the same.
In a pidgin, non-real assembler I'm making up:
MOV AX,A_VARIABLE
MOV BX,B_VARIABLE
CMP AX,BX ;; or maybe AND AX,BX or XOR AX,BX because flags
JNE THEY_ARE_NOT_EQUAL
JMP THEY_ARE_EQUAL
...
THEY_ARE_EQUAL:
...
THEY_ARE_NOT_EQUAL:
In 'C' if I am really concerned about this, I will:
const bool TheThingMatches = (strcmp(a,b)==0);
Edit: It ate my line breaks.
To support sorting. The result of a "comparison" does not imply the testing for equality or equivalence. I can "compare" lots of things, and my results are not strictly boolean. A "comparison" often implies one thing is "better" or "worse" or the "same" as another thing.
Believe it or not, there are people who are capable of figuring out C's cute little "round trip through the integers" trick, but who would rather not deal with that bullshit every time they want to compare two values of non-numerical type. It's not elegant, it's not natural, it's only "obvious" to those of us who have had the standard workarounds for C's inexpressiveness drilled into our skulls, and if it were any different, we wouldn't bother with comparison operators in the first place!
I mean, I get that it's fun to squeeze useful semantics out of terse code, especially in an environment as constrained as C. But please don't act like the rest of us are stupid just because what you regard as elegant, we regard as more of a clever hack to be put up with for want of a simple equality operator.
everything is "numerical" or can be interpreted as such. It's not C-specific at all, it's just a fact of how computers fundamentally operate. I suspect that might be why this issue is so divisive: if you started low-level with hardware, Asm and the like, then C does feel natural and obvious. If you started high-level with some other HLL, one that abstracts and hides this "essence", it won't.
Pointers are another example of something that is obvious to some but a huge mass of confusion and frustration to others. I've taught programming (mostly Asm and C), and this is quite common. You're not stupid, but you just aren't in the right perspective to understand it.
Those who are strong advocates of functional programming and wonder why others don't see the elegance probably think the same way about me. ;-)
I understand pointers. I understand integer-based encoding. I'm a firmware programmer, I started with FORTRAN and C-with-classes-style C++, I get how computers work. And do you know what makes computers work? Abstractions. Integers are just an abstraction on top of bit vectors are just an abstraction on top of memory are just an abstraction on top of flip-flops, on top of gates, transistors, digital circuitry, analog circuitry, the laws of electromagnetism -- the only reason we are able to construct something as complex as a pocket calculator and have it work at all is clear, mathematical abstraction. The fact that, in 2016, using such a fundamental abstraction as equality of non-numerical values requires anything beyond the two characters "==" is patently absurd.
My "frustration" is not a result of having trouble grasping first-year C.S. concepts. Nor is it the result of the mild incovenience of specifically having to use "strcmp" instead of "==". It's the result of working in an industry where the value of anything beyond first-year C.S. concepts is completely unrecognized, because it's not "how computers fundamentally operate." Both low-level and high-level computational abstractions are useful, and trying to accomplish anything interesting in a system which completely eschews one class of abstraction in favor of the other, whether it's C or Haskell, is hell.
But hey, it beats the hell out of Javascript :)
I just think "ah, it's a yes we have no bananas" and stop thinking about it :) It's nonzero cognitive load but it's not much.
I've dealt with enough active-low/inverting hardware such that "on" = 0 that it actually doesn't bother me at all. Assembly has that all through it at times.
Compared to reading code where people treat cell [1] as the first significant cell of an array ( usually translated from FORTRAN ) , this is a picnic.
/* This is for making a type that can be compared but not calculated.
* Use it like `(const void *) _StrcmpResult[i]` for i = 0, 1 or 2.
* i = 0 indicates less, 1 indicates equal, and 2 indicates greater. */
extern const char _StrcmpResult[2];
const void *_Strcmp(const char *a, const char *b);
#define strcmp(a, op, b) (_Strcmp((a), (b)) op (const void*) &_StrcmpResult[1])
Now you are almost unable to incorrectly use this interface: `strcmp(a, <, b)` and `strcmp(a, !=, b)` etc. works, `strcmp(a, -, b)` does not compile (because we've casted to `const void*`), `strcmp(a, =, b)` also does not compile (because `_Strcmp()` is not a lvalue). Other incorrect uses will likely result in compile errors, though in possibly more obscure ways.