Genii Weblog

I like C/C++, but there are times it is annoying

Wed 23 May 2007, 04:07 PM

by Ben Langhinrichs
I have been programming in C (and C++ when classes were necessary and such) for a long, long time, and I am pretty used to the common gotchas.  Every C programmer runs into the equals sign mistake, where something like that below is used:

if (status = 3)

which sets the value of status to 3 and then evaluates to TRUE since any non-zero value is TRUE, instead of what was meant, which was 

if (status == 3)

which simply evaluates to TRUE or FALSE.  There are many similar issues, but I ran into one I don't ever remember seeing before, even though it was devilishly easy to create.

In a class, there is a boolean value called IsConnected.  In a method within that class, I frequently use the code:

if (this->IsConnected) 

to test that value, since this is the class object itself.  But in a recent interim version of CoexEdit, I accidentally wrote:

if (this-IsConnected) 

Now, if this had been any other pointer other than the current class object, such a mistake would likely show up as a syntax error, since there is no IsConnected local variable, but in this case, there is a local value for IsConnected.  In fact, it was 0, so the object was not connected, so:

if (this->IsConnected) 

would evaluate to FALSE.  But in this case, the wonderful world of pointer arithmetic in C reached out and bit me.  The construction

if (this-IsConnected) 

was perfectly valid, and simply subtracted zero from the pointer represented by this.  Of course, this meant that the statement always evaluated to TRUE, since, as I said before, every non-zero value is TRUE.  Ouch!  Easy to describe, easy to fix, but harder than you would think to figure out since my mind simply saw the construct it expected.

Just in case you think a software developer's life is always easy.

Copyright 2007 Genii Software Ltd.

What has been said:

592.1. Mika Heinonen
(05/24/2007 02:59 PM)

I never understood why people still write object->method() in C++. I always write object.method() and never had any problems. Also things like status=3 and status==3 can and should (in my opinion) be avoided by using true OOP syntax, like status.setvalue(3) and status.comparevalue(3).

592.2. Devin Olson
(05/24/2007 03:07 PM)

Ouch! That sounds like it was a HUGE frustration trying to figure out.


592.3. Ben Langhinrichs
(05/24/2007 04:17 PM)

I'm afraid I am not a strong believer in "true OOP syntax". I use objects when they make sense, but I have never found they make life as wonderful as some seem to feel, but I understand that is a heretical opinion.

592.4. Mika Heinonen
(05/24/2007 04:56 PM)

Well, fortunately C++ also allows the definiton of your own class operators, so you could make your own = and == operators, however there starts a bit dilemma if you want to stay generous. C++ does not support templates of templates, which leads you to "hardcode" each class bound to certain base type (like int, String() class, etc..). So I don't know what's better if you want to stay clean of all hardcoding, do everything with methods, or write a preprocessor for the preprocessor :)

592.5. Ben Langhinrichs
(05/24/2007 05:31 PM)

Part of the problem is that I often need to switch to C instead of C++, so I don't tend to use anything which won't work equally well in either. I know that is a choice which causes problems sometimes, but I tend to find it leads to tighter, more clean code than defining my own operators and other such actions which may be good for error detection but can both cause confusion and slow down the system considerably. I never have any classes tied to types, but just use the base types themselves.