Why I don't write 'if (NULL == foo)' in C code

November 21, 2005

One of the infamous trivial bugs in C code is accidentally writing '=' instead of '==' in conditional expressions; you get assignment instead of equality checking. One common piece of advice for avoiding this is to reverse the order of the check, putting the constant first. This way, if you accidentally write 'NULL = foo' instead of the == version, you'll get a compile time error.

I can't stand to write this version, because it looks wrong to me. I recently figured out why it looks so wrong: because it doesn't match my mental narrative of the code.

I write code by thinking 'if foo is NULL ...' and typing 'if (foo == NULL)', a pretty direct mapping. Similarly, if I am reading code I scan the 'if (..)' and go to the narrative version. When I try to reverse the condition the narrative comes to a jarring stall; I am thinking 'if foo is NULL' but writing something that looks like 'if NULL is foo'.

For me, the benefits of reversed conditionals just aren't worth putting up with code that looks wrong but isn't. (We already know that ugly code is confusing code.)

Comments on this page:

From at 2005-11-22 16:19:16:

Fortunately C compilers are good about warning about it. Unfortunately, some C compilers don't warn about it if you parenthesize it. I'm not sure how far this goes, but it may mean ( (x == 0) && (y == 1) ) is vulnerable to the bug. (Double-parentheses as markup: crappy idea.)

Anyway, I don't do it either, for much the same reason.

However, lately I've started writing '0 == strcmp(x,y)'. The reason for this is twofold.

First is the stylistic choice to only use '!' when dealing with a true boolean (that is, something which is either 0 or 1). This is commonplace style advice for things like 'foo == NULL'--I used to write that as '!foo' quite happily, but I have been won over on this front.

So I've decided to apply that to strcmp, too, and never write (!strcmp(x,y)) anymore. But what I've discovered is that 'strcmp(x,y)==0' doesn't fit the narrative 'x is the same string as y' very well. This is particularly true if x or y are particularly long. You know that they are being compared, but you don't know the sense of the test until you reach the very end. 'x equals y', 'x is greater than y', etc. don't defer that linguistically at all. Given the choice of making the comparison type be a suffix, as is traditional, or a prefix, I've decided that since it's always short ("0 >", "0 <", "0 >=", "0 <=", "0 ==", or "0 !="), it belongs at the front.

It looks weird, but I'm getting used to it, at least for "0 ==" and "0 !=". I'm not sure I can stand to do it for inequality comparisons, since it'll slow deciphering what it means much more.


By cks at 2005-11-23 02:18:27:

If I wrote C code that used strcmp() very much, I suspect I would wind up wrapping it in a #define'd macro I called STREQ() or something like that. (The bstring library that I like has a biseq() function with this interface.)

I'm inconsistent on the whole '!foo' versus 'foo == NULL' issue; sometimes I write it one way, sometimes the other, even in the same program. I don't think it's wrong per se, since C defines pointers to be boolean false when they are 0 (aka NULL).

As far as ((..)) for markup: DWiki suffers from the standard WikiText problem that there aren't enough good markup characters to go around. I wanted a paired set of delimiters for literal typewriter text, and {{..}} and [[..]] were already used for other things.

Written on 21 November 2005.
« Weekly spam summary on November 19th, 2005
How to fiddle with Firefox .jar files relatively easily »

Page tools: View Source, View Normal, Add Comment.
Login: Password:
Atom Syndication: Recent Comments.

Last modified: Mon Nov 21 00:50:18 2005
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.