Departments


We Have Mail


Dr. Plauger,

I don't wish to take up your time with a religious war, even though of this article's 26 rules I strongly disagree with at least 15, but it is too delicious to point out that one hazard of re-writing C is doing it wrong, and the

enum E_BOOL {TRUE, FALSE};
has the constants reversed.

Also, it really is worth noting that for all of the so-called warnings generated by Listing 2, their style sheet and tool fail to detect the major potential for disaster. Line 8 will fail catastrophically if the program has been invoked without an argument and argv[1] is garbage. Their "improved" Listing 4 has the same logic error.

Personally, I find the style of Listing 2 perfectly acceptable, even without comments, but I would check argc first! I can't imagine even a Cobol programmer needs a comment for the declaration:

SHORT choice;
(I might add that I have been using C for less than two years and have been a professional programmer for all of ten months.)

Andrew Lazarus
staff computer scientist

Dear editor:

In the July issue Ballay and Storn gave a number of C coding conventions, some of which are actually formatting conventions. Coding and formatting conventions are very contentious issues among C programmers. An article like that should elicit a lot of responses. Here's as much of my response as I think CUJ readers can be expected to take.

I respecfully disagree on some matters.

Replacement of operators such as && and // is not helpful for experienced C programmers, it introduces additional identifier conflicts, and it keeps syntax-directed editors from doing their job.

At one time in my life, I advocated replacing braces with the words BEGIN and END, so that "these important delimiters can be more easily seen with the naked eye." It had been recommended by K&R, so I felt I was on fairly safe ground. Then I got a text editor that did brace matching, and I changed my mind.

The use of additional parentheses in expressions like

(c== '\t')||(c=='\n')
provides a "more readable layout" only for those crippled by too much exposure to Pascal. In Pascal, you have to use parentheses, because that language uses the wrong operator priorities. In C, they just make the code look crowded and amateurish.

There is really no good reason to write sum+=a*b instead of sum=sum+a*b, but there are two excellent reasons to use the += operator in an expression like sum[3*i+2*j+1]=+a*b. Despite the lip service given to "common subexpression elimination" as an optimization criterion, few compilers will do it in a case like this. And when the programmer has to write the same subexpression twice, there's always the danger of making a mistake that the compiler can't catch.

The definition:

enum E_BOOL {TRUE,FALSE}
will set TRUE to 0 and FALSE to 1. Everyone else on earth does it the other way around. Is that a misprint?

I enthusiastically agree on other matters.

The use of LOCAL instead of static really does help. static outside a function body actually means local.

Help stamp out tabs! I have a filter that expands tabs to two, four, or eight spaces, and I use it on incoming C code. (Any good C programmer can write such a filter in about 15 minutes.) Even so, I spend quite a bit of time cleaning up code that has literally become ragged by passing through editors with different tab spacings. Incidentally, there is a tendency for C programmers to overindent. Two spaces is enough to make the structure clear. Indenting four or eight spaces often causes deeply nested code to slide off the right edge of the screen or page.

Implicit tests for zero must go. Actually, this is an attempt to compensate for the pitifully weak typing of C — in particular, the lack of a Boolean type. It should be noted that most C compilers generate no more code for if(x!=0) than they do for if (x).

I do use several standard type names to ensure portability between compilers with different int word lengths, although the names WORD and DWORD are to be preferred over SHORT and LONG, which merely capitalize the ambiguity. However int shouldn't be banished entirely. When length isn't important, a variable should normally be declared int so the compiler can choose the best length for the target machine and avoid needless type conversions in expression evaluations.

Ballay and Storn's article is mercifully short. The right conventions, the proper CASE tool, or whatever, will never be a substitute for good judgement on the part of the programmer. In programming, as in writing, sometimes an "error" is just what is needed.

Finally, there are problems with C that can't be cured by programming or formatting style. Weak typing is one. I've written a couple of critiques that have been floating around the Internet (comp.lang.c) and CompuServe (the UNIX Forum, Library 8 Lang/Programming) for several years.

Philip J. Erdelsky
4092 Ohio Street
San Diego CA 92104
75746.3411 @compuserve.com

Editor,

I read through the enjoyable article, "A Tool for Checking C coding Conventions." I make a lot of points here. While I agree with many things they said, and agree a convention (even a bad one) is often better than no convention,

1) I can't agree to "change the language," as in:

#define EQ ==
#define NEQ !=
In both cases, EQ and NEQ differ by one character. I cannot see how it is "better" to use EQ/NEQ instead of ==/!= (unless you insist on using Cobol-like programming!).

The advantage is not to confuse equality with assignment. However, gcc (which also runs on MS-DOS) picks this out with -Wall. For example, if you do:

   if(a = 5)
gcc will say:

foo.c:6: warning: suggest parentheses
around
   assignment used as truth value
forcing you to do:

   if((a = 5))
Actually, I like the following style better:

   if(5 == a)
which will not compile if you do

   if(5 = a)
I like this style.

2) The authors talk about a code fragment:

   while(c: ' ' || c == '\t' | c == '\t')
      c = getc(f)
you won't mistake a bitwise OR for a logical OR if you:

   while((c EQ ' ' ) OR (c EQ '\t') OR
      (c EQ '\n'))
   c = getc(f)
I find confusing bit-operators and logical operators is rare, and easy to find. Far harder is debugging incorrect logic. (Do I want an AND (&&) or an OR ( | | ?)

3) Changing the language with the preprocessor leads to obfuscated C. I happened to be reorganizing and came across Allen Holub's Viewpoint column in Dr. Dobbs Journal (August 1986, p.16), which talks about a number of things I agree with. Allen makes a number of excellent points in his column:

I'd much rather look at straight C syntax (especially modifying someone else's code) then have to figure out "My C."

I also don't like the idea of doing:

#define EXPORT
#define IMPORT  extern
#define LOCAL   static
What's the matter with extern, nothing, and static? Injecting more symbols increases the complexity and makes the code harder to understand.

I understand Steve Bourne had a style where he made C look like Pascal:

#define BEGIN  {
#define END    }
was in the original Bourne shell.

4) I also think the authors missed something very important by not discussing project organization and prototypes. I didn't see anything about prototypes. Was this neglected or cut off due to space? One of ANSI C's biggest advantages is prototypes. In order to properly use prototypes on a multi-file project,

It is crucial to include the prototype where the function is, because I've seen too many cases where File1 has:

extern float foo(float a);

float bar(float f)
{
   return foo(f) + 1.0;
}
and File2 has:

void foo(void)
{
   printf("I ain't gonna work\n");
}
Obviously the prototype is incorrect, but the compiler and the linker won't complain, which defeats the purpose of prototyping.

I generate all my prototypes automatically with cproto (a tool by Chin Huang, chin.huang@canrem.com). I find this a very good way to develop software (the prototyping becomes automatic).

marty
Member of the League of Programming Freedom
leisner@sdsp.mc.xerox.com
leisner@eso.mc.xerox.com

I've made no individual comments on the stylistic issues raised by the above letters on the Ballay and Storn article. I know style is very much a matter of taste. Interestingly enough, there were far more comments on what style rules to enforce than on whether they should be enforced. You can always change the former, given a commitment to the latter.

As an aside, Steve Bourne was an Algol 68 fan. He did his best to make C look like that language, not Pascal. — pjp

Dear Mr. Plauger,

Are there any technical differences (or even "clarifications") between ANSI C and ISO C? I have a much dog-eared copy of the ANSI C standard. Is there any reason I should pick up the ISO version? I vaguely recall reading (back when I had Usenet access) that the ISO version renumbered all the sections, and dropped the Rationale part. Were any technical changes made in the process?

Also, I'm wondering if there is a less expensive source for ISO standards than ANSI? ANSI lists a price of $130 for the ISO C standard.

Thanks in advance!

JR (John Rogers)
CompuServe: 72634,2402
72634.2402@CompuServe.com

Your understanding is correct. ISO C is substantially the same as ANSI C, save for renumbering. A much cheaper source is The Annotated ANSI C Standard, reviewed here recently. It has a botched page, and opinions vary on the quality of the annotation, but it's certainly cheaper than ANSI. — pjp

Dear Sir:

I have countless volumes on C Programming, but none deal with command-line parsing. I have yet to see an article in CUJ (on any other mag for that matter) on the subject. I have examined several source programs that show parsing by "case," but they deal only with single letters and not multiple letters or attached file names or specs. I have read in at least two books on C "style" that case statements should be avoided as much as goto for reason of clarity. I haven't been able to reason an efficient and clean method and hope that you could enlighten us programmers with an acceptable style of command-line parsing. I have been programming since the SWTPC 6800 kit was out, mostly in Basic and Cobol. I could proclaim that I'm an expert at spaghetti BASIC. Since learning C, I have decided to write all my source neatly, efficiently, and structured. I know I could thrash around the command line looking for entries but I would rather be set straight as to the method that professionals use.

Any help would be much appreciated.

Jim Pazarena
Box 550 — 405 2nd Avenue
Queen Charlotte, BC
V0OT 1S0

Actually, command-line parsing is less structured than you think. In my Whitesmiths, Ltd. days, we religiously used two functions called getflags and getfiles to do nearly all such parsing. Others use some version of a function called getopt. A random walk through UNIX source code, or code inspired by that corpus, will show you that most parsing is both ad hoc and idiosyncratic. Pick a style and stick with it. — pjp

Editor,

I have a minor nit to pick.

In you June 1994 CUJ editorial you make the statement "You can't buy a C compiler for a major host without finding a C++ compiler attached." I take it this means that you do not consider UNIX "A Major Platform?"

HPUX is sold with a bundled non-ANSI C compiler. You may buy (and many of us do) an extra cost ANSI C compiler. If you want a C++ compiler, that is yet another package. Sun sells their C compiler without C++ if I am not mistaken. IBM's AIX is the same story also I believe. As a matter of fact the only combination C/C++ compilers that come to mind are Microsoft's, Borland's, and GNU's.

The point that I am trying to make is that this is yet another indication of just how DOS/Microsoft Windows-centric CUJ has become. It is unfortunately not the only magazine suffering from this malady. As a matter of fact it isn't even the worst. I recently dropped my subscription to Dr. Dobbs that I had carried for 15 years for this very reason.

I do still find CUJ highly useful and informative. I just wanted to point out how this particular statement struck me.

I believe that covering C++ as well is C is an important function for CUJ so don't misunderstand this as a flame against the name change.

Thanks for your time.

Stan Brown
Factory Automation Systems
Atlanta Ga.
stanb@netcom.com
404-996-6955

I am a UNIX user from the earliest days and have often promoted that system as one still superior in many ways to others. Nevertheless, I have to notice that it is outsold 10 or 20 to 1 by other systems. Our contributors reflect the same ratio in the proportion of UNIX-based (or UNIX-tolerant) articles they submit. I am enough of a capitalist, and a Darwinian, to accept that this endangers the status of UNIX as a "major" system, in the eyes of many programmers. If we fail to give UNIX the attention and respect you (or I) may feel it deserves, it is neither because of a blind spot nor an active effort to ignore the system. — pjp

Dear Plauger:

When I was younger, they'd hand you a computer, with a little book perhaps describing all the nifty features inadequately, and tell you, "You don't need to know about that; that's all handled in the" drive card, monitor card, you-name-it system software, etc. Which, roughly translated, means that the intelligent Bengladeshi lad who did all this stuff has returned home and nobody in the company has a clue how it works, but it seems to work, and that's the way they like it. Trade secret, you know.

Then came the IBM PC. IBM, of all people, told us everything.

Now of course we're back in the woods. What I'd like to do this time is examine memory. I want to see what bytes are in memory. Somehow or other, whenever I'm involved with a machine for a while, I want to do this. But mine is a 386 machine. I can't find a program that will do that. I can tell what bytes have been mapped into memory; I can tell what the operating system, or QEMM, or who knows what thinks should be in memory; but I don't actually have a tool that will tell me what is in actual physical memory.

Why do I care? Because the PC's DMA hardware doesn't know what QEMM or the operating system thinks; it deals with physical memory, which I can't see! I was going to write a program that does single-byte DMA transfers, so I can see what's actually in memory, but documentation I've been reading for one of the 5 million memory handlers chillingly suggests that some arrogant twit of a system software may intercept my I/O port references, and change them into what it thinks ought to be DMAed.

Twitch, twitch.

J. G. Owen
Software Engineer
31 Darby Drive
South Huntington, New York 11746

Welcome to the world of complexified software. Know that it, too, will pass. — pjp