"Writing bug free C code" thoughts

F

Francine.Neary

I was browsing through this on the internet (http://www.duckware.com/
bugfreec/index.html). I have to say, it seems pretty awful to me.

One example early on: he suggests using
#define CompilerAssert(exp) extern char _CompilerAssert[(exp)?1:-1]
for compile-time debugging, but this seems to me to be a bug in itself
- doesn't declaring a variable starting with _ provoke undefined
behavior by incroaching on the implementation's namespace?

And then he goes on to recommend using hungarian notation (yeuch!)...
in chapter 8, he says
"If you do not have access to a C++ compiler, use the standard C /* */
comment form"
implying he thinks it's a good thing to compile C with a C++ compiler!
And some of the advice is just bizarre:
"auto variables should be defined one per line"
(why? do whatever makes the meaning clearest. And is it OK to define
multiple static variables per line?), and
"using the comma operator can lead to code that is hard to read and
maintain. It is best to avoid using it"
- I often find the comma operator helps make code briefer.

The main problem seems to be that he wants to teach other people
style, while he has absolutely no taste himself - the following macros
speak for themselves:

#define LOOP(nArg) { int _nMax=nArg; int loop; \
for (loop=0; loop<_nMax; ++loop)
#define LLOOP(lArg) { long _lMax=lArg; long lLoop; \
for (lLoop=0; lLoop<_lMax; ++lLoop)
#define ENDLOOP }

Bring me the sick bucket!

In summary, I'd advise anyone to avoid this like the plague.
 
R

Richard Heathfield

(e-mail address removed) said:
I was browsing through this on the internet (http://www.duckware.com/
bugfreec/index.html). I have to say, it seems pretty awful to me.

One example early on: he suggests using
#define CompilerAssert(exp) extern char _CompilerAssert[(exp)?1:-1]
for compile-time debugging, but this seems to me to be a bug in itself
- doesn't declaring a variable starting with _ provoke undefined
behavior by incroaching on the implementation's namespace?

Yes, it does.
And then he goes on to recommend using hungarian notation (yeuch!)...

Yes, it is! :)
in chapter 8, he says
"If you do not have access to a C++ compiler, use the standard C /* */
comment form"
implying he thinks it's a good thing to compile C with a C++ compiler!

Which isn't actually possible. A C++ compiler compiles C++ code, not C
code. Or, to put it another way, a compiler takes a source program as
input and translates it into another representation (either another
language or object code, which might anyway be regarded as another
language). The translation is done according to certain rules. If you
use a C++ compiler, it's done according to C++ rules. If you use a C
compiler, it's done according to C rules. And if you use a Pascal
compiler, it's done according to Pascal rules. So you pick the rules
you want, and use the appropriate compiler. If you write a program
according to the rules of C, and then compile it with a C++ compiler,
you're just asking for trouble, misunderstandings, and much
head-scratching.
And some of the advice is just bizarre:
"auto variables should be defined one per line"
(why?

I can think of a few reasons. Firstly, it don't arf make it a lot
quicker to delete a redundant declaration! :) Secondly, it means you
can give a winged comment to every object, if that kind of thing takes
your fancy. Thirdly, it completely sidesteps the

FILE * in, out;

problem. Fourthly, some people think it looks neater and easier to read.
do whatever makes the meaning clearest.

Right. In my view, that normally means one decl per line.
And is it OK to define
multiple static variables per line?),

What do *you* think? The same reasons apply as to auto objects. But
again, "do whatever makes the meaning clearest" is the right rule here.
and
"using the comma operator can lead to code that is hard to read and
maintain. It is best to avoid using it"
- I often find the comma operator helps make code briefer.

Brevity may be the soul of wit, but it is rarely the best guide to
writing good code. (Neither is verbosity, of course.) Do whatever makes
the meaning clearest.
The main problem seems to be that he wants to teach other people
style, while he has absolutely no taste himself - the following macros
speak for themselves:

#define LOOP(nArg) { int _nMax=nArg; int loop; \
for (loop=0; loop<_nMax; ++loop)
#define LLOOP(lArg) { long _lMax=lArg; long lLoop; \
for (lLoop=0; lLoop<_lMax; ++lLoop)
#define ENDLOOP }
Oof.

Bring me the sick bucket!

In summary, I'd advise anyone to avoid this like the plague.

I'll take a look at the site - not because I distrust your advice, but
out of sheer natural curiosity.
 
R

Richard Heathfield

Richard Heathfield said:
(e-mail address removed) said:


I'll take a look at the site - not because I distrust your advice, but
out of sheer natural curiosity.

I have now done so, and I concur wholeheartedly with your sentiments.
 
B

Ben Pfaff

Richard Heathfield already made most of the comments that I
would. But I have a little bit to add.

One example early on: he suggests using
#define CompilerAssert(exp) extern char _CompilerAssert[(exp)?1:-1]
for compile-time debugging, but this seems to me to be a bug in itself
- doesn't declaring a variable starting with _ provoke undefined
behavior by incroaching on the implementation's namespace?

Yes. Also, such a macro could only be used a single time in a
given scope. I've seen people sidestep that by token-pasting
__LINE__ into the name, though.
The main problem seems to be that he wants to teach other people
style, while he has absolutely no taste himself - the following macros
speak for themselves:

#define LOOP(nArg) { int _nMax=nArg; int loop; \
for (loop=0; loop<_nMax; ++loop)
#define LLOOP(lArg) { long _lMax=lArg; long lLoop; \
for (lLoop=0; lLoop<_lMax; ++lLoop)
#define ENDLOOP }

I've seen fairly good reason to embed partial loops into macros,
in particular for linked list traversal as seen in the Linux
kernel, but the good versions of these macros don't embed
unbalanced braces and they do something more useful than
counting.
 
O

Old Wolf

I was browsing through this on the internet (http://www.duckware.com/
bugfreec/index.html). I have to say, it seems pretty awful to me.

Same here, I'm just agreeing with you but nobody
else had replied yet so I thought I would.
One example early on: he suggests using
#define CompilerAssert(exp) extern char _CompilerAssert[(exp)?1:-1]
for compile-time debugging, but this seems to me to be a bug in itself

Certainly is
in chapter 8, he says
"If you do not have access to a C++ compiler, use the standard C /* */
comment form"
implying he thinks it's a good thing to compile C with a C++ compiler!

Might have been written by Paul Hsieh then ;)
"auto variables should be defined one per line"
"using the comma operator can lead to code that is hard to read and
maintain. It is best to avoid using it"

The main problem seems to be that he wants to teach other people
style, while he has absolutely no taste himself

You could argue that good style makes it less likely you'll write a
bug.
For example, conceivably putting 1 variable per line makes it
more obvious if you forget to initialize a variable (hence the
distinction between auto and static).

This seems pretty specious to me apart from the basics (e.g.
indenting loops). A better way to not write bugs is to learn
the language better.
 
F

Francine.Neary

I can think of a few reasons. Firstly, it don't arf make it a lot
quicker to delete a redundant declaration! :) Secondly, it means you
can give a winged comment to every object, if that kind of thing takes
your fancy.

I rarely find it useful to comment a specific variable. Either it's
used in one place for something simple, in which case a generic name
like i or p gets this across, or else it's a key variable used
repeatedly, in which case give it a descriptive name... but in that
case it's self-documenting.
Thirdly, it completely sidesteps the

FILE * in, out;

problem.

This doesn't arise if you do
FILE *in, *out;
or even
FILE *in,*out;
instead.
What do *you* think? The same reasons apply as to auto objects. But
again, "do whatever makes the meaning clearest" is the right rule here.

I agree - I was just making the point that for some reason the author
of this website singled out auto variables as being unsuitable for
multiple declarations on a line, as if static variables need different
treatment in this regard.
 
F

Francine.Neary

One example early on: he suggests using
#define CompilerAssert(exp) extern char _CompilerAssert[(exp)?1:-1]
for compile-time debugging, but this seems to me to be a bug in itself
- doesn't declaring a variable starting with _ provoke undefined
behavior by incroaching on the implementation's namespace?

Yes. Also, such a macro could only be used a single time in a
given scope.

I don't think that's right - I think you can have multiple identical
declarations of the same thing (with extern, no storage is allocated,
it just tells the compiler that if it sees a symbol called
_CompilerAssert then it should believe that to be an array of char).
 
D

Duncan Muirhead

I rarely find it useful to comment a specific variable. Either it's
used in one place for something simple, in which case a generic name
like i or p gets this across, or else it's a key variable used
repeatedly, in which case give it a descriptive name... but in that
case it's self-documenting.
<snip>
One case where I think individual variable (and field, argument etc)
comments are very useful is to describe the units of things that
represent physical quantities, especially if there are a variety of units
used. In "double speed;" the name is descriptive, but I think
"double speed; /* knots */" is far more informative. I seem to recall a
space vehicle crashed into Mars because of units mismatch...
 
D

dykeinthebox

I was browsing through this on the internet (http://www.duckware.com/
bugfreec/index.html). I have to say, it seems pretty awful to me.
[snip]

In summary, I'd advise anyone to avoid this like the plague.

I agree. The following is an excerpt from these pages (2.1.9 Adjacent String
Literals):

===========
It is also a good way to place macro arguments in a string.

Placing macro arguments in a string literal
#define PRINTD(var) printf( "Variable " #var "=%d\n", var )

PRINTD() works by using the stringizing operator (#) on the macro argument,
namely #var. This places the macro argument in quotes and allows the
compiler to concatenate the adjacent string literals.
===========

Consider what happens when this macro is being used in the following way

PRINTD( 6%2 );
 
I

Ian Collins

Duncan said:
<snip>
One case where I think individual variable (and field, argument etc)
comments are very useful is to describe the units of things that
represent physical quantities, especially if there are a variety of units
used. In "double speed;" the name is descriptive, but I think
"double speed; /* knots */" is far more informative. I seem to recall a
space vehicle crashed into Mars because of units mismatch...
Better for the name to define the units - a name that requires a
descriptive comment is a smell.
 
R

Richard Heathfield

(e-mail address removed) said:
This doesn't arise if you do
FILE *in, *out;
or even
FILE *in,*out;
instead.

Yes, I know that, and you know that. Nevertheless, one-decl-per-line
/does/ sidestep this issue.
 
T

Tor Rustad

Richard said:
(e-mail address removed) said:


Yes, I know that, and you know that. Nevertheless, one-decl-per-line
/does/ sidestep this issue.

As long as the compiler will detect such a typo, there is no need for such a
side-step IMO. There are other typo's, far more interesting, which the
compiler will silently accept.

Readability, is a sufficient reason for having only one decl-per-line.
 
R

Roland Pibinger

I was browsing through this on the internet
(http://www.duckware.com/bugfreec/index.html).
I have to say, it seems pretty awful to me.

One example early on: he suggests using

OMG, you found a few examples that you don't like and now you slate
the whole book.
#define CompilerAssert(exp) extern char _CompilerAssert[(exp)?1:-1]
for compile-time debugging, but this seems to me to be a bug in itself
- doesn't declaring a variable starting with _ provoke undefined
behavior by incroaching on the implementation's namespace?

namespace? In C?
implying he thinks it's a good thing to compile C with a C++ compiler!

at lest for someone who speaks of 'the implementation's namespace'
And some of the advice is just bizarre:
"auto variables should be defined one per line"

wow, an earthshaking advice, deserves the utmost counteraction
The main problem seems to be that he wants to teach other people
style, while he has absolutely no taste himself - the following macros
speak for themselves:

you have never seen such macros in a C program?
Bring me the sick bucket!
In summary, I'd advise anyone to avoid this like the plague.

This books is about application design using C. It not merely presents
some more or less clever code snippets but techniques for larger
applications, esp. wrt infomation hiding. I know only very few other
sources that do the same. I don't like some of the macros, too. But
that does no harm to the book (everyone has his/her own style). In
sum, I recommend the book to the informed reader. Thanks to your
inappropriate critique it now gets more attention.
 
C

Chris Dollin

Roland said:
#define CompilerAssert(exp) extern char _CompilerAssert[(exp)?1:-1]
for compile-time debugging, but this seems to me to be a bug in itself
- doesn't declaring a variable starting with _ provoke undefined
behavior by incroaching on the implementation's namespace?

namespace? In C?

`namespace` is a perfectly good abstract concept, even if the language
has no keyword for it.

That's even if you ignore the struct/label/variable name space distinction
that C makes.
 
C

Charlton Wilbur

RP> OMG, you found a few examples that you don't like and now you
RP> slate the whole book.

If the author can't get the simple things right, how can he be
expected to get the difficult and complex things right? And writing
bug free code is a lot more difficult and complex than it seems.
>> #define CompilerAssert(exp) extern char
>> _CompilerAssert[(exp)?1:-1] for compile-time debugging, but
>> this seems to me to be a bug in itself - doesn't declaring a
>> variable starting with _ provoke undefined behavior by
>> incroaching on the implementation's namespace?

RP> namespace? In C?

Yes, namespace. The term used by the Standard is actually 'name space.'

RP> you have never seen such macros in a C program?

I have seen horrifically bad code. This does not make that code an
exemplar of good style.

Charlton
 
S

shadowman

Duncan said:
<snip>
One case where I think individual variable (and field, argument etc)
comments are very useful is to describe the units of things that
represent physical quantities, especially if there are a variety of units
used. In "double speed;" the name is descriptive, but I think
"double speed; /* knots */" is far more informative. I seem to recall a
space vehicle crashed into Mars because of units mismatch...
But IMO, a better alternative would be something more like:

double speedInKnots;
 
D

Duncan Muirhead

But IMO, a better alternative would be something more like:

double speedInKnots;
In simple cases, maybe, but I find complex formulae using
long names (e.g. speedInKnots, towLoadInDecaNewtons) to
be more difficult to read than with short names.
 
A

Al Balmer

As long as the compiler will detect such a typo, there is no need for such a
side-step IMO. There are other typo's, far more interesting, which the
compiler will silently accept.

While the compiler might know that

FILE out;

is a typo, it has no way to tell whether

int *ip1, ip2;

is a typo.
Readability, is a sufficient reason for having only one decl-per-line.

Yes.
 
R

Richard Tobin

As long as the compiler will detect such a typo, there is no need for such a
side-step IMO.
[/QUOTE]
However its not a typo.
double * x, y;

And the compiler will correctly not detect it.

If it *had* been a typo, the compiler would almost certainly have
generated a diagnostic when the variable was used.

No typo in declaration, no diagnostic:

double * x, y;
...
*x = y;

Typo in declaration, diagnostic:

double * x, y;
...
x = y;

-- Richard
 
M

Mark McIntyre

As long as the compiler will detect such a typo, there is no need for such a
side-step IMO.

However its not a typo.
double * x, y;

--
Mark McIntyre

"Debugging is twice as hard as writing the code in the first place.
Therefore, if you write the code as cleverly as possible, you are,
by definition, not smart enough to debug it."
--Brian Kernighan
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,537
Members
45,020
Latest member
GenesisGai

Latest Threads

Top