Coding standards

J

jdallen2000

I see Google now suppresses any leading
white space in the messages I post.
Sorry about that. I'll find a better way to post
before I show code samples again.

James
 
K

Keith Thompson

for (x = in_sig->beg_x; x < in_sig->end_x; x++)
for (y = in_sig->beg_y; y < in_sig->end_y; y++)
for (z = in_sig->beg_z; z < in_sig->end_z; z++) {
val = 0;
for (dx = conv_k->beg_x; dx < conv_k->end_x; dx++)
for (dy = conv_k->beg_y; dy < conv_k->end_y; dy++)
for (dz = conv_k->beg_z; dz < conv_k->end_z; dz++) {
val += in_sig->dat[x+dx][y+dy][z+dz]
* conv_k->dat[dx][dy][dz];
}
out_sig->dat[x][y][z] = val;
}
[snip]

Unfortunately, we can't tell what kind of indentation you're using,
since group.google.com decided leading blanks aren't significant (a
violation of their "Don't be evil" policy IMHO). I've complained to
them about this and received what appears to be a form letter in
response.

You can fool Google into keeping the indentation by preceding each
line with a non-blank character:

| blah(blah) {
| blah;
| blah;
| }

Or you can use a different news server if you have access to one.
 
D

Dietmar Schindler

Richard said:
There's a way to use sizeof that looks as if it's a function call...

A way to use sizeof looks as if it's a function call only to a person
that is unaware of the fact that sizeof is an operator and, for types,
believes that a type can be a function argument.

(I don't suggest that you, Richard, are such a person, but am writing
this to work against misconceptions.)

Dietmar
 
N

Natt Serrasalmus

infobahn said:
I don't.


You are wrong to infer that. I do in fact understand boolean variables.
I also understand that in almost all cases, foo() does not return a
boolean variable, but an int.

When a logical expression is evaluated in C, it is evaluated as an integer
expression and it determines if the integer is zero or non-zero. Sounds
boolean doesn't it? Two states: either zero or non-zero.

If foo() is truly boolean in nature,
then I am perfectly prepared to write if(foo(bar)) rather than
if(foo(bar) != 0)

Nothing in C is truly boolean. There is no C type for boolean. There are
only integers that are evaluated in logical expressions to be either zero or
non-zero. While that sounds like boolean values, you are technically correct
in claiming that is not truly boolean, but as far as the C language is
concerned the logical alternatives are zero or non-zero. Notice also that if
you do a logical not (!) on any non-zero value you will get zero. Perform
the same operation on zero and you get a non-zero value.
But the fact that you find the form "annoying" suggests that you need to
relax a little.


Absolutely. And a boolean variable can only answer one of those
questions, which is why so few of my functions return boolean
variables.

I should say that none of your functions return boolean variables since
there is no such thing as a boolean variable in C. Unless of course you
create one through typedef, but what are you actually doing if you do that?
You are defining an enumerated data type that can have two values which are
either zero or some non-zero value. Are you beginning to get the feeling
that C considers integers to be boolean values that are of two kinds, zero
and non-zero when expressed in a logical context?
No, it should be obvious to any C programmer worth their pay that
the result of strcmp is not boolean, but relational (negative,
zero, or positive).

The C language treats the result as a boolean value in a logical context,
it's either zero or non-zero.
We do, however, care whether the result is negative, zero, or positive.

Why? Normally, I only care if the strings are the same or not. The distance
between each other is not something I can normally do anything about.
I, however, do not encourage early exit from a function. In all too
many cases, this makes the control flow harder for a maintenance
programmer to follow. Maintenance programmers are often under a lot
of pressure to fix a problem quickly, in code they don't know very
well. Anything we can do to help them out is a bonus, and writing
your functions to have all the structure of spaghetti bolognaise is
not helping anyone.

If you think early exits from functions results in spaghetti, then you don't
know what spaghetti is. From an earlier post:

Consider the (pseudo) code examples below:

int func(arglist)
{
(declarations)
int retval = BADSTATUSVALUE;
void *pointer;

if(condition1)
{
pointer = malloc(SOMESIZE);
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
if(condition2)
{
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
if(condition3)
{
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
if(condition4)
{
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
while(condition5)
{
long_line_that_ should_
be_broken_up_because_it_is_so_long_and_indented;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
retval = GOODSTATUSVALUE;
}
} /* condition4 */
} /* condition3 */
} /* condition2 */
} /* condition1*/

free(pointer);
return retval;
}


I'm sure most of us have seen code similar to the above. Now consider:

int func(arglist)
{
(declarations)
void *pointer;

if(!condition1)
return BADSTATUSVALUE:

pointer = malloc(SOMESIZE);
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
if(!condition2)
{
free(pointer);
return BADSTATUSVALUE;
}

codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
if(!condition3)
{
free(pointer);
return BADSTATUSVALUE;
}
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
if(!condition4)
{
free(pointer);
return BADSTATUSVALUE;
}
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
while(condition5)
{
long_code_line_that_doesn't_have_to_be_broken;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
codeline;
}

free(pointer);
return GOODSTATUSVALUE;
}

Now then, this second example is far easier to deal with. The extreme
indentation has been eliminated, the distant brace matching has been
eliminated and the retval variable has been optimized away. This results in
several less things to keep track of. With the less indentation, fewer long
lines need to be broken up.

Also consider how the first example reads in the sense of ordinary language:
if condition1 keep going if condition2 keep going if condition3 keep going
etc.

as opposed to:

if not condition1 stop if not condition2 stop if not condition3 stop etc.

This is more consistent with a language that refers to traffic signals as
stoplights not golights.

But nobody has to maintain the code in K&R's book. Also, whilst I
greatly admire both K, R, and their book, the day I use K&R as a
style guide is the day I grow an extra arm.

I'm not recommending K&R as a style guide, in fact there are aspects of
their style I don't care for. I was, instead, intending to point out how
they use the return values of functions such as strcmp as if they were
boolean types and also how they use them to prompt early returns from
functions. This is why C works the way it does as far as logical expressions
are concerned. The intent of the designers of the language becomes clear. It
intends for logical expressions to transcend the limits of pure boolean
algebra.
I am fortunate enough not to have got used to early exit from functions.
I am very happy for you if you are used to it, but I have developed my
own style based on my own reasoning and logic, and I'm quite happy to
use that style.

You might want to consider if your own reasoning and logic isn't a little
too much your own.
Your style for you; my style for me.


Oh, I do that already, and have done for many years.



There, I must agree with you. What makes this worse is when foo() is not
a boolean function, and yet its result is still compared against a
"boolean" symbol such as TRUE or FALSE.


Oh, I see. You're complaining against code structure.

I'm complaining against awkward code structure.
I prefer:

if(foo(bar))
{
rc = baz();
}
else
{
rc = NONZEROSTATUSVALUE;
}
return rc;

Do you have a problem with the nesting depth here?

What you wrote should be written as:

return foo(bar) ? baz() : NONZEROSTATUSVALUE;

Why should anyone have to keep track of rc when it is not needed? Why should
anyone have to follow several lines of flow of control when none are needed?

In the code you provided, it is too easy for that harried maintenance
programmer to just stick in trial bits of code inside each of the brace
pairs until they stumble upon something that takes care of the problem,
nevermind that it can create another problem or obscure the purpose of the
code. In the case I provide, the maintenance programmer should have no
trouble understanding the single line of code and if they don't (they
shouldn't be coders for a living), they had better figure it out before they
attempt any modifications. Requiring maintenance programmers to actually
know what they are doing is not a bad thing.

However assuming that you could have provided a more complicated example, I
would have expected it to be similar to the form in the re-posted (pseudo)
code example 1. Having given that example, you should have no trouble seeing
how early exits from functons improve the readability of the code.
Yes, that's what I thought you meant before.


This code, whilst correct, will have the newbies (and some older hands)
reaching for their K&Rs. Better: c = (a == b);

If it gets someone reaching for their K&Rs then so much the better. They
should be up to speed on the language. Those of us who are shouldn't have to
dumb down our code for those who aren't up to speed. In fact anyone who had
to reach for their K&R to understand that piece of code falls into the
category I was complaining about before, those who don't understand the use
of boolean values in C. As far as the parentheses are concerned, I find it a
trivial issue. Either way should not be a problem for anyone. If adding the
parentheses helps you feel better, I don't have a problem with that. The one
place I do have a problem with extraneous parentheses is when they are used
for every return value as in:

return (somestatusvariable);

When I see that it makes return look like a function call, which it isn't.
Those who code that way don't seem to understand how return works. Having
said that I don't mind something like:

return ((some_expression) operator ((some_expression) operator
(some_expression)));

Where the parentheses can clarify the meaning. For a return value like that,
I'd probably also include a comment that explained the ramifications of the
expressions.
I would prefer c = (a != b);

While I don't see any real difference, I have to wonder why you'd find the
second way better. The way I put it preserves the sense of the original
code, but again I don't see one as having any value over the other.
I didn't find them particularly funny. Just silly.



Mmmm. Well, just pray you never have to maintain my code.

I probably never will, but I have had to fix code that follows your
conventions and typically the problem arose from a maintenance programmer
who followed the same conventions and couldn't be bothered to truly
understand what the code was doing. Chances are they were intimidated by the
bulk of the code. So they just stuck a few lines of code in, maybe some
initializers and by a hacking band-aid approach managed to fix the bug they
were assigned to fix. Nevermind that they made the code even worse, even
bulkier and even harder to maintain for the next person.
Not in my newsreader, they aren't.

In mine they were and I used spaces, not tabs.
Well, the compiler doesn't need them. The human sometimes finds them
useful, so I put them in /all/ the time.

This human finds them to clutter up the code. I've asked several coders who
adopt your method when braces are necessary and when they aren't. I've never
met one who knew. These are people who are being paid to write C code.

The purpose of the brace is to define the beginning and end of a compound
statement. When you put braces where they are not needed, I read it as the
compiler does as in "open brace: start compound statement" then you put a
single statement where a compound statement is expected. That would be
comparable to putting punctuation in English where none is expected.

(Charlie Brown writes a letter:

Dear, Grandma,
I, had a, nice day, at school, today,. We, studied punctuation, marks.
Today, we, learned about, the, comma,. )

For a start, they should be close enough together that you can
see which ones match which other ones.

Why should I have to see it if they aren't needed?
And even if they aren't,
if you line them up
{
like this
}

you don't have to worry about which ones match which, because it's
obvious.

I really don't have to worry about it if they aren't there.
And even if it weren't obvious, decent modern editors can
whizz you from { to } and back in the blinking of an eye.

If they aren't there at all, I don't have to ask my editor which ones match.
 
N

Natt Serrasalmus

E. Robert Tisdale said:
Idioms are for idiots!


That's two questions.


Because the result returned by strcmp is not zero

It is one of the possible return values.
and any non zero result used as a conditional
is [implicitly] converted to true.

There's no conversion. There is no "true" in C. Logical expressions are
evaluated as integers having a value of either zero or non-zero.
Unfortunately, the rest of us must write code
that is obvious to C programmers *not* worth their pay
as well as C programmers who are worth their pay.
This means that I write explicit code
rather than relying upon implicit conversions.
I would write:

if (0 != strcmp(string1, string2))

to detect strings which don't match.

You would pander to idiots instead of firing them. We've already seen how
nobody likes this form.
It isn't my responsibility to ferret out incompetent programmers.

Then why do you dumb down your code to accomodate them?
 
N

Natt Serrasalmus

Alan Balmer said:
But that's just not true, except for the I/O functions. Most others
return some value as a result, not as a diagnostic.

I will write "if (a)" providing 'a' is a boolean.

As I pointed out in other posts, there is no boolean in C. Logical
expressions are evaluated as integers having a value of zero or non-zero.

If not, I will write
if (a != 0). If that bothers you, so be it.

If a is an integer, then it can have a value of zero or non-zero and
therefore can be treated as if it were a boolean value. Therefore, why go to
the trouble of doing the comparison?
 
N

Natt Serrasalmus

Keith Thompson said:
Personally, I don't think of the result of strcmp() as a boolean
value. It's effectively a tri-state value, one of <0, 0, or >0
depending on the result of the comparison.

As I pointed out elsewhere, there are no boolean values in C. C evaluates
logical expressions as integers having two possible values: zero and
non-zero. So any function that returns an integer value can be used as if it
were a boolean expression, where the boolean values are zero and non-zero.

I prefer an explicit
comparison:

if (strcmp(string1, string2) != 0) ...

If the function's name implied that it tests whether the arguments
differ, I might feel differently about it.

What do you think strcmp stands for? I usually think of it as "string
compare", meaning "do the strings compare?". By that sense, the function's
name implies that it tests whether the arguments differ.
YMMV, of course, and any C programmer needs to be able to understand
the use of strcmp() in a condition (though I confess it takes me a
moment of thought).

[...]
if(foo(bar) == TRUE) /* where true is a macro defined as some non-zero
value */
{
(indented code for the entire rest of the function)
}
return somestatusvariable;

when it should be

if(!foo(bar))
return NONZEROSTATUSVALUE;
(code for the entire rest of the function now not indented so far)

On this I agree wholeheartedly. Never compare a value to TRUE or
FALSE; if such a comparison makes sense, the value is already a
condition and should be used as one.
(note also that some may have different notions as to what TRUE should be
defined as: -1, 1 etc. which makes the test against TRUE not just
idiomatically awkward, but potentially dangerous.)
Yup.

[...]
if(a == b)
{
c = FALSE;
}
else
{
c = TRUE;
}

which should be

c = !(a == b);

Or

c = (a != b);

(Yes, I like the parentheses, even though they're not strictly
necessary.)

[...]
I hope its mindshare is dimishing. I would have written the above as:

if (!cap_issubset(inheritable,
cap_combine(target->cap_inheritable,

current->cap_permitted)))
goto out;

That's indented much too deeply for my taste. Are you using hard tabs
with a non-standard tabstop setting?

I might write:

if (!cap_issubset(inheritable,
cap_combine(target->cap_inheritable,
current->cap_permitted)))

It looked like this when I posted it. I used spaces, not tabs.

...
This way arguments to functions are lined up.
[snip]

--
Keith Thompson (The_Other_Keith) (e-mail address removed)
<http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*>
<http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
 
N

Natt Serrasalmus

Christian Bau said:
Keith Thompson said:
Natt Serrasalmus said:
news:[email protected]... [...]
Which "we" are you talking about? It doesn't include me.

I write if(foo(bar) != 0)

I find that form really annoying and when I see it in others code. It
suggests to me that the person who wrote it doesn't understand boolean
variables and the C idiom that was established with the C standard
library.
The idiom I am referring to is that functions should return a value
that
answers the question "Did anything go wrong and if so what was it?". By
that
idiom then it should be obvious to any C programmer worth their pay
that

if(strcmp(string1, string2))

means "Did anything go wrong (not match up) when comparing these two
strings?" (if I wanted to know how far off they were I'd save the
return
value to a variable and evaluate that, but rarely does anyone ever care
how
far off the comparison was, other functions may have more interesting
non-zero return codes.)

Personally, I don't think of the result of strcmp() as a boolean
value. It's effectively a tri-state value, one of <0, 0, or >0
depending on the result of the comparison. I prefer an explicit
comparison:

if (strcmp(string1, string2) != 0) ...

If the function's name implied that it tests whether the arguments
differ, I might feel differently about it.

First, by definition it is a multi-valued function and not a boolean
function.

There's no such thing as a boolean function in C. See my other posts in this
thread.

Second, if it was a boolean function, then the person who
called it "strcmp" and not "strnotequal" should be shot.

This is a failure to understand the C idiom that I was reffering to earlier
in the thread.
 
C

Christian Bau

"Natt Serrasalmus said:
As I pointed out in other posts, there is no boolean in C. Logical
expressions are evaluated as integers having a value of zero or non-zero.

This is anal. "Boolean" is an abstract concept, which is easily
implemented in C. Try to learn about abstraction.
 
B

Ben Pfaff

Natt Serrasalmus said:
As I pointed out elsewhere, there are no boolean values in C.

C99 has _Bool, which has only two values: 0 and 1. This is about
as boolean as it gets.
 
V

Victor Nazarov

Natt said:
Natt said:
(e-mail address removed) wrote: [snip]
I write if(foo(bar) != 0)


I find that form really annoying

I don't.

I write
if (foo (bar) != 0)
Nothing in C is truly boolean. There is no C type for boolean. There are
only integers that are evaluated in logical expressions to be either zero or
non-zero. While that sounds like boolean values, you are technically correct
in claiming that is not truly boolean, but as far as the C language is
concerned the logical alternatives are zero or non-zero. Notice also that if
you do a logical not (!) on any non-zero value you will get zero. Perform
the same operation on zero and you get a non-zero value.

If is usually intendent to provide an early exit from the function on
error. Really I dont think that
if (!p)
or
if (p == 0)
makes any sence, if we show that this /if/ compares p with an invalid
value, and we'll exit. But when we use strcmp all three values are valid
and we must choose one. In this case we usually continue our task, there
is no boolean statement "this value is invalid for our task" wich we
express with the if statement.
[snip]
int func(arglist)
{
(declarations)
void *pointer;

if(!condition1)
return BADSTATUSVALUE:

pointer = malloc(SOMESIZE);
codeline;
codeline; [snip]
codeline;
codeline;
if(!condition2)
{
free(pointer);
return BADSTATUSVALUE;
}

codeline;
codeline; [snip]
codeline;
if(!condition3)
{
free(pointer);
return BADSTATUSVALUE;
}
codeline;
codeline; [snip]
codeline;
if(!condition4)
{
free(pointer);
return BADSTATUSVALUE;
}
codeline;
codeline; [snip]
codeline;
while(condition5)
{
long_code_line_that_doesn't_have_to_be_broken;
codeline;
codeline;
[snip]
codeline;
}

free(pointer);
return GOODSTATUSVALUE;
}

Now then, this second example is far easier to deal with. The extreme
indentation has been eliminated, the distant brace matching has been
eliminated and the retval variable has been optimized away. This results in
several less things to keep track of. With the less indentation, fewer long
lines need to be broken up.

Also consider how the first example reads in the sense of ordinary language:
if condition1 keep going if condition2 keep going if condition3 keep going
etc.

as opposed to:

if not condition1 stop if not condition2 stop if not condition3 stop etc.

This is more consistent with a language that refers to traffic signals as
stoplights not golights.

Agread. by I prefer:

int foo (/* ... */)
{
FILE *f1p = NULL, *f2p = NULL;
char *s = NULL;
int res = -1;

/*
...
codelines
...
*/
f1p = fopen (fn, fmode);
if (!f1p)
goto fail;
/*
...
codelines
...
*/
f2p = fopen (fn, fmode);
if (!f2p)
goto fail;
/*
...
codelines
...
*/
s = malloc (len);
if (!s)
goto fail;
/*
...
codelines
...
*/
res = 0
fail:
free (s);
if (!f2p)
fclose (f2p);
if (!f1p)
fclose (f1p);
return res;
}

to simplify the cleanup.
 
I

infobahn

Natt said:
When a logical expression is evaluated in C, it is evaluated as an integer
expression and it determines if the integer is zero or non-zero. Sounds
boolean doesn't it? Two states: either zero or non-zero.

You missed my point. Consider the following function names:

int IsPrinterReady(PRINTER *);
int IsLeapYear(int);
int Sum(int *, size_t);
int HasTransferCompleted(DATA *);
int OpenDatabase(DB *);

All these functions return int. It is quite obvious, however, to
the experienced, intelligent, or just plain common-sense eye that
three of the five are designed to answer a Boolean question. That
is, they return a number representing 'true' or a number representing
'false'. The others do not.
If foo() is truly boolean in nature,

Nothing in C is truly boolean. There is no C type for boolean.

Perhaps you should read up on C's _Bool type, introduced 5 years ago.
There are
only integers that are evaluated in logical expressions to be either zero or
non-zero. While that sounds like boolean values, you are technically correct
in claiming that is not truly boolean, but as far as the C language is
concerned the logical alternatives are zero or non-zero. Notice also that if
you do a logical not (!) on any non-zero value you will get zero. Perform
the same operation on zero and you get a non-zero value.

I suspect this is a paradigm thing. We just don't see data the same
way. So we're unlikely ever to agree on this.
I should say that none of your functions return boolean variables since
there is no such thing as a boolean variable in C.

Wrong in fact and wrong in spirit. Even before C introduced _Bool,
it was possible to use ints (and other integer types) as Boolean
values, by the simple method of only ever writing a 0 or a 1 to
them.
The C language treats the result as a boolean value in a logical context,
it's either zero or non-zero.

If you think strcmp is a boolean function, you are missing out on a
significant part of its functionality.
Why? Normally, I only care if the strings are the same or not. The distance
between each other is not something I can normally do anything about.

Some of us need to sort strings occasionally. If you don't, fine.

If you think early exits from functions results in spaghetti, then you don't
know what spaghetti is.

Oh, but I must beg to differ. I used to generate tons of the stuff
in the days when I wrote BASIC programs.
From an earlier post:

Consider the (pseudo) code examples below:

Bleargh. All snipped, and replaced with:
int func(arglist)
{
(declarations)
int retval = BADSTATUSVALUE;

if(condition1)
{
retval = otherfunc(whatever);
}
return retval;
}


Now then, this second example is far easier to deal with.

No, it's not. It's stupidly long and has far too much going on.

Learn to modularise.

What you wrote should be written as:

return foo(bar) ? baz() : NONZEROSTATUSVALUE;

s/should/could/

I prefer my form.
Why should anyone have to keep track of rc when it is not needed? Why should
anyone have to follow several lines of flow of control when none are needed?

You could eliminate the function call completely. You could stick
everything in main(). I am not convinced that this would lead to
more readable code.
In the code you provided, it is too easy for that harried maintenance
programmer to just stick in trial bits of code inside each of the brace
pairs until they stumble upon something that takes care of the problem,
nevermind that it can create another problem or obscure the purpose of the
code. In the case I provide, the maintenance programmer should have no
trouble understanding the single line of code and if they don't (they
shouldn't be coders for a living), they had better figure it out before they
attempt any modifications. Requiring maintenance programmers to actually
know what they are doing is not a bad thing.

In the code you provided, there's little to stop that same harried
maintenance programmer from sticking trial bits of code alongside the
conditional operator's operands, a la:

return foo(bar) ? stuff, baz() : otherstuff, NONZEROSTATUSVALUE;

Your format hardly protects against this - and nor can it. Nor,
indeed, should it be expected to. And neither should mine.
However assuming that you could have provided a more complicated example, I
would have expected it to be similar to the form in the re-posted (pseudo)
code example 1. Having given that example, you should have no trouble seeing
how early exits from functons improve the readability of the code.

You have certainly demonstrated how early exits from functions appear
to encourage long, poorly written, rambling functions.
If it gets someone reaching for their K&Rs then so much the better.
Touche'.

They should be up to speed on the language.

I agree, but nobody should have to remember precedence tables.
return (somestatusvariable);

When I see that it makes return look like a function call, which it isn't.

Well, I don't like that either, as it happens.
[...] I have had to fix code that follows your
conventions and typically the problem arose from a maintenance programmer
who followed the same conventions and couldn't be bothered to truly
understand what the code was doing. Chances are they were intimidated by the
bulk of the code. So they just stuck a few lines of code in, maybe some
initializers and by a hacking band-aid approach managed to fix the bug they
were assigned to fix. Nevermind that they made the code even worse, even
bulkier and even harder to maintain for the next person.

This has little to do with code conventions and a lot to do with
the quality of maintenance programmers.
In mine they were and I used spaces, not tabs.

Perhaps you were using a proportional font (shrug).

This human finds them to clutter up the code. I've asked several coders who
adopt your method when braces are necessary and when they aren't. I've never
met one who knew. These are people who are being paid to write C code.

Scary! But it's another reason always to put them in.
The purpose of the brace is to define the beginning and end of a compound
statement. When you put braces where they are not needed, I read it as the
compiler does as in "open brace: start compound statement" then you put a
single statement where a compound statement is expected. That would be
comparable to putting punctuation in English where none is expected.

The C language definition does not, as far as I can tell, ascribe
a purpose to the brace character; the only hint we get is in the
grammar, which explicitly lays down that a compound statement is
composed of an *optional* declaration-list and an *optional*
statement-list (so the compound statement can legally be empty).
Furthermore, a statement-list comprises either a statement or a
statement-list followed by a statement. So the grammar specifically
caters for a compound statement containing only one statement.
(Charlie Brown writes a letter:

Dear, Grandma,
I, had a, nice day, at school, today,. We, studied punctuation, marks.
Today, we, learned about, the, comma,. )

C is not English, and the analogy is a poor one.
 
K

Keith Thompson

Natt Serrasalmus said:
As I pointed out in other posts, there is no boolean in C. Logical
expressions are evaluated as integers having a value of zero or non-zero.

C99 does have a type "bool", and literals "false" and "true".
(Actually, it has a type _Bool; "bool" is a typedef, and "false" and
"true" are macros, defined in <stdbool.h>.) But C99 retains the C90
rules about zero vs. non-zero for conditions.
If not, I will write

If a is an integer, then it can have a value of zero or non-zero and
therefore can be treated as if it were a boolean value. Therefore, why go to
the trouble of doing the comparison?

Since C90 doesn't make an explicit distinction between a variable that
can hold any of 2**N distinct integer values (an int) and a variable
that can hold a logically false (zero) or true (non-zero) value (an
int), we as programmers can choose to make that distinction ourselves.

If a variable "a" can meaningfully hold more than two distinct values
(e.g., a count of something), I prefer to write "if (a != 0)" rather
than "if (a)". If I'm using it to hold a true/false condition --
i.e., if I care whether it's zero or non-zero, but I never care which
non-zero value it happens to have -- then I'll write "if (a)". I'll
also give it a better name than "a", one that tells the reader at a
glance that it's a condition, perhaps something like "done" or
"valid".

A good example of this is the is*() functions in <ctype.h>. For
example, isdigit(c) returns a non-zero value if and only if its
argument is a digit. The standard says nothing about which non-zero
value it returns; it might be 1, or it might be 12345. Thus it's
logically a Boolean, and I'll use "if (isdigit(c))".

On the other hand, strcmp() returns a negative, zero, or positive
value depending on the relationship between its arguments. Even if I
don't happen to care at the moment whether it's negative or positive,
I still prefer to write "if (strcmp(a, b) == 0)" rather than
"if (!strcmp(a, b))", because the result of strcmp() isn't logically a
Boolean. (If C had the three-way if statement of ancient Fortran,
strcmp() would be a good opportunity to use it, but thankfully it
doesn't.)

Similarly, I prefer to compare the result of fopen() explicitly to
NULL rather than using it directly as a condition.

Your mileage may vary, of course, and if I see code that uses
if (!strcmp(a, b))
or
if (fp=fopen("foo.txt", "R"))
it won't give me too much trouble.
 
K

Keith Thompson

infobahn said:
Even before C introduced _Bool, it was possible to use ints (and
other integer types) as Boolean values, by the simple method of only
ever writing a 0 or a 1 to them.

Actually, you can implement Boolean values with ints by writing zero
or non-zero to them, and by referring to them only in ways that work
the same way for any non-zero value. Treating 2 or -1 as "true" is
perfectly valid.
 
R

Richard Bos

[ Guys! Please learn to snip... ]
What do you think strcmp stands for? I usually think of it as "string
compare", meaning "do the strings compare?". By that sense, the function's
name implies that it tests whether the arguments differ.

OTOH, it's also possible to think of it as "_how_ do these strings
compare?", the answer being either "s1 is smaller", "they're equal", or
"s2 is smaller".
Since this is the meaning that the Standard requires the function to
provide (no matter that _you_ only care, in a given line of code,
whether one of these three is true), I think it's the most appropriate
one.
It looked like this when I posted it. I used spaces, not tabs.

Either, IMO, is overly indented, but yours showed up at this end exactly
as far indented (the cap_combine under the 'l' of inheritable, and the
third line under the 'p' of cap_inheritable) as shown above, except that
it hadn't wrapped yet. Are you perhaps using a proportional font for
reading Usenet? If so, consider that spaces in proportional fonts are
generally about half as wide as those in fixed-width fonts.

Richard
 
R

Richard Bos

infobahn said:
You missed my point. Consider the following function names:

int IsPrinterReady(PRINTER *);
int IsLeapYear(int);
int Sum(int *, size_t);
int HasTransferCompleted(DATA *);
int OpenDatabase(DB *);

All these functions return int. It is quite obvious, however, to
the experienced, intelligent, or just plain common-sense eye that
three of the five are designed to answer a Boolean question. That
is, they return a number representing 'true' or a number representing
'false'. The others do not.

Beg to differ. IsLeapYear(), obviously yes. IsPrinterReady(), yes. But I
could imagine HasTransferCompleted() to write the address of the next
completed data buffer through its argument, and return the number of
unprocessed complete data buffers. In all these cases, except perhaps
IsLeapYear() if I'm certain I'm not going to pass dates before 1572, I'd
certainly want to read the specs before using them no matter how obvious
they look.
You have certainly demonstrated how early exits from functions appear
to encourage long, poorly written, rambling functions.

No, he hasn't. He's demonstrated that muddle-headed programmers find
themselves encouraged to do so by whatever style they use, but that's
hardly surprising.
I agree, but nobody should have to remember precedence tables.

Oh? We shouldn't remember that * goes above +, and both above &&? It's
not generally necessary to remember the details surrounding &, &&, = and
==, but I'd certainly want any competent programmer to remember the
basics.

Richard
 
A

Alan Balmer

As I pointed out in other posts, there is no boolean in C. Logical
expressions are evaluated as integers having a value of zero or non-zero.
You keep repeating this as if it is something you just learned ;-)
Boolean is a concept, not just a data type. You can use truth values
in C (and even call them Booleans in C99) without ever knowing the
integer values they represent.
If not, I will write

If a is an integer, then it can have a value of zero or non-zero and
therefore can be treated as if it were a boolean value. Therefore, why go to
the trouble of doing the comparison?

My programs are written not only for the compiler to understand, but
for a human to understand. Variables are used in a way which is
natural to the problem domain. Pretending an integer is a truth value,
or vice versa, does not contribute to understanding.
 
M

Michael Wojcik

Please provide proper attributions when you quote on Usenet. For someone
so concerned with imposing consistency, you're observing rather poor
netiquette.
[True Style] is a common style, but its mindshare seems to
be diminishing.

I'll believe you, though it saddens me. Pursuing the analogy
with English, frequent misspellings eventually make their
way into the dictionary, but that doesn't make misspelling
right.

Unfortunately, your understanding of English is flawed, so your
analogy holds no water. English "misspellings" are neither right nor
wrong; they may be common or uncommon, and they may be accepted or
not by a particular group, but there is no English language standard,
and no generally-recognized arbiters of the language.

To return to an example from your previous post: putting periods and
commas before closing quotation marks, regardless of their proper
scope in the sentence, does not "improve" your writing (or anyone
else's). It shows that you are willing to kowtow to a particular
convention - and a pointless one at that, one which was invented
solely to preserve fragile lead type. Since few documents are set in
lead type these days, there's no justification for continuing that
convention. Contrary to your claim, I think you'll find no evidence
that preserving this convention for the sake of "consistent punctua-
tion" has any benefit whatsoever for readability. Few readers would
even notice.
The True Style was never universally agreed, of course,
but was in very widespread use among the most elite C
programmers.

So you say. Do you have any actual empirical evidence to support
this? What's your rubric for determining membership in "the most
elite C programmers"? What constitutes "very widespread use"?
Good and bad code may be written in any
style of course, but I'm sure there is (was?) a strong
positive correlation between coding in True Style and
positive traits like clarity and modularity.

What an odd thing to be sure of. I'd rather think it's just the
sort of question that tends to produce unfounded belief.
(I'm not
saying True Style is intrinsically conducive to good
coding practice, just that those who use it tend to have
learned from or emulate the Masters.)

Ah, Cargo Cult Programming.
(1) I was mostly observing this style already, a major
exception being brace placement. I was writing
}
else
{
but in True Style this is written
} else {
The second form is simply better than the first! The former
form disconnects the keyword "else" from both its antecedent
and postcedent

Nonsense. I can read more than one line at a time, and so can
every programmer I've ever known.
and is distracting to read.

For you, perhaps. I've not heard this complaint from anyone else.

What constitutes a "distraction" in this context? Presumably the
reader is concerned primarily with semantics - what algorithm the
source expresses - and so a distraction would be some feature of
the source which called attention away from semantics; in short, a
syntactic element which caught the reader's attention. I suspect
then that "distraction" is equivalent to syntactic surprise - which
leads to the unsurprising conclusion that what is "distracting to
read" is any style the reader is not accustomed to.
Also it wastes
two lines on the screen compared with the latter form, and this
is a "big deal." The left-braces in Non-true code use up
considerable vertical space and therefore more scrolling is
needed to understand a function. Smaller fonts might alleviate
this problem, but that's not an option for those of us
with poor eyesight.

By this argument, you should eliminate whitespace wherever possible.

The "compact representation" argument is a non-starter in style wars.
Clearly either extreme is unacceptable, but that tells us nothing
about the wide range of reasonable alternatives. There is a wealth of
research on the effects of layout on readability (which I suspect few
style police have read), but what I've read of it indicates - again
unsurprisingly - that differences among readers and aspects of
particular documents are far too important to make any very specific
rules generally applicable.

In this particular case, there's certainly ample anecdotal evidence
that plenty of potential source-code readers prefer the additional
vertical whitespace to compactness.
(2) I was proud to emulate the style of so many Masters.

Cargo cult.
(3) As I examined various software I noticed the strong correlation
between True Style and good traits like clarity and modularity.

Observer error, I suspect. Did you do any formal analysis to prove
that this observation was in fact present? People are notoriously
poor at accurately observing correlations.
(4) Whitespace arrangement isn't all that important but
uniformity would be convenient.

What sort of convenience does it provide?

--
Michael Wojcik (e-mail address removed)

Auden often writes like Disney. Like Disney, he knows the shape of beasts --
(& incidently he, too, might have a company of artists producing his lines) --
unlike Lawrence, he does not know what shapes or motivates these beasts.
-- Dylan Thomas
 
C

CBFalconer

Richard said:
.... snip ...

Oh? We shouldn't remember that * goes above +, and both above &&?
It's not generally necessary to remember the details surrounding
&, &&, = and ==, but I'd certainly want any competent programmer
to remember the basics.

As far as I am concerned, multiplicative has precedence over
additive which has precedence over logical will do. Anything
further should be explicitly indicated with the use of the all
purpose parentheses. The mere existence of further levels in C is
a fault IMNSHO. Yes, I know there are no precedence levels in C,
just Backus-Naur descriptions.
 
C

Christian Bau

CBFalconer said:
As far as I am concerned, multiplicative has precedence over
additive which has precedence over logical will do. Anything
further should be explicitly indicated with the use of the all
purpose parentheses. The mere existence of further levels in C is
a fault IMNSHO. Yes, I know there are no precedence levels in C,
just Backus-Naur descriptions.

I always wanted to write down a grammar that allows exactly those C
expressions that I find acceptable and disallows those that I don't like
(for example "a << b + c" - is it (a << b) + c or a << (b + c)? ) Never
found the time for it, but it shouldn't be too difficult.
 

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

Similar Threads


Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,057
Latest member
KetoBeezACVGummies

Latest Threads

Top