17. Style

comp.lang.c FAQ list · Question 17.1

Q: What's the best style for code layout in C?

A: Kernighan and Ritchie, while providing the example most often copied, also supply a good excuse for disregarding it:

The position of braces is less important, although people hold passionate beliefs. We have chosen one of several popular styles. Pick a style that suits you, then use it consistently.

It is more important that the layout chosen be consistent (with itself, and with nearby or common code) than that it be ``perfect.'' If your coding environment (i.e. local custom or company policy) does not suggest a style, and you don't feel like inventing your own, just copy K&R.

Each of the various popular styles has its good and bad points. Putting the open brace on a line by itself wastes vertical space; combining it with the following line makes it hard to edit; combining it with the previous line prevents it from lining up with the close brace and may make it harder to see.

Indenting by eight columns per level is most common, but often gets you uncomfortably close to the right margin (which may be a hint that you should break up the function). If you indent by one tab but set tabstops at something other than eight columns, you're requiring other people to read your code with the same software setup that you used. (See also the Indian Hill Style Guide.)

The elusive quality of ``good style'' involves much more than mere code layout details; don't spend time on formatting to the exclusion of more substantive code quality issues.

See also question 17.2.

References: K&R1 Sec. 1.2 p. 10
K&R2 Sec. 1.2 p. 10

comp.lang.c FAQ list · Question 17.2

Q: How should functions be apportioned among source files?

A: Usually, related functions are put together in one file. Sometimes (as when developing libraries) it is appropriate to have exactly one source file (and, consequently, one object module) per independent function. Other times, and especially for some programmers, numerous source files can be cumbersome, and it may be tempting (or even appropriate) to put most or all of a program in a few big source files. When it is desired to limit the scope of certain functions or global variables by using the static keyword, source file layout becomes more constrained: the static functions and variables and the functions sharing access to them must all be in the same file.

In other words, there are a number of tradeoffs, so it is difficult to give general rules. See also questions 1.7, 1.9, 10.6, and 10.7.

comp.lang.c FAQ list · Question 17.3

Q: Here's a neat trick for checking whether two strings are equal:

if(!strcmp(s1, s2))
Is this good style?

A: It is not particularly good style, although it is a popular idiom. The test succeeds if the two strings are equal, but the use of ! (``not'') suggests that it tests for inequality.

Another option is to define a macro:

	#define Streq(s1, s2) (strcmp((s1), (s2)) == 0)
which you can then use like this:
	if(Streq(s1, s2))

Another option (which borders on preprocessor abuse; see question 10.2) is to define

	#define StrRel(s1, op, s2) (strcmp(s1, s2) op 0)
after which you can say things like
	if(StrRel(s1, ==, s2)) ...
	if(StrRel(s1, !=, s2)) ...
	if(StrRel(s1, >=, s2)) ...

See also question 17.10.

comp.lang.c FAQ list · Question 17.4

Q: Why do some people write if(0 == x) instead of if(x == 0)?

A: It's a trick to guard against the common error of writing

if(x = 0)
If you're in the habit of writing the constant before the ==, the compiler will complain if you accidentally type
	if(0 = x)
Evidently it can be easier for some people to remember to reverse the test than to remember to type the doubled = sign. (To be sure, accidentally using = instead of == is a typo which even the most experienced C programmer can make.)

On the other hand, some people find these reversed tests ugly or distracting, and argue that a compiler should warn about if(x = 0). (In fact, many compilers do warn about assignments in conditionals, though you can always write if((x = expression)) or if((x = expression) != 0) if you really mean it.)

References: H&S Sec. 7.6.5 pp. 209-10

comp.lang.c FAQ list · Question 17.4b

Q: I've seen function declarations that look like this:

extern int func __((int, int));
What are those extra parentheses and underscores for?

A: They're part of a trick which allows the prototype part of the function declaration to be turned off for a pre-ANSI compiler. Somewhere else is a conditional definition of the __ macro like this:

	#ifdef __STDC__
	#define __(proto) proto
	#define __(proto) ()
The extra parentheses in the invocation
	extern int func __((int, int));
are required so that the entire prototype list (perhaps containing many commas) is treated as the single argument expected by the macro.

Additional links: further reading

comp.lang.c FAQ list · Question 17.5

Q: I came across some code that puts a (void) cast before each call to printf. Why?

A: printf does return a value (the number of characters printed, or an error code), though few programs bother to check the return values from each call. Since some compilers (and lint) will warn about discarded return values, an explicit cast to (void) is a way of saying ``Yes, I've decided to ignore the return value from this call, but please continue to warn me about other (perhaps inadvertently) ignored return values.'' It's also common to use void casts on calls to strcpy and strcat, since the return value is never surprising.

References: K&R2 Sec. A6.7 p. 199
Rationale Sec. 3.3.4
H&S Sec. 6.2.9 p. 172, Sec. 7.13 pp. 229-30

comp.lang.c FAQ list · Question 17.6

Q: If NULL and 0 are equivalent as null pointer constants, which should I use?

A: See question 5.9.

comp.lang.c FAQ list · Question 17.7

Q: Should I use symbolic names like TRUE and FALSE for Boolean constants, or plain 1 and 0?

A: See question 9.4.

comp.lang.c FAQ list · Question 17.8

Q: What is ``Hungarian Notation''? Is it worthwhile?

A: Hungarian Notation is a naming convention, invented by Charles Simonyi, which encodes information about a variable's type (and perhaps its intended use) in its name. It is well-loved in some circles and roundly castigated in others. Its chief advantage is that it makes a variable's type or intended use obvious from its name; its chief disadvantage is that type information is not necessarily a worthwhile thing to carry around in the name of a variable.

References: Simonyi and Heller, ``The Hungarian Revolution''

comp.lang.c FAQ list · Question 17.9

Q: Where can I get the ``Indian Hill Style Guide'' and other coding standards?

A: Various documents are available for anonymous ftp from:

	Site:			File or directory:

	ftp.cs.washington.edu	pub/cstyle.tar.Z
			(the updated Indian Hill guide)

	ftp.cs.toronto.edu	doc/programming
				(including Henry Spencer's
				``10 Commandments for C Programmers'')

	ftp.cs.umd.edu		pub/style-guide

You may also be interested in the books The Elements of Programming Style, Plum Hall Programming Guidelines, and C Style: Standards and Guidelines; see the Bibliography.

See also question 18.9.

comp.lang.c FAQ list · Question 17.10

Q: Some people say that goto's are evil and that I should never use them. Isn't that a bit extreme?

A: Programming style, like writing style, is somewhat of an art and cannot be codified by inflexible rules, although discussions about style often seem to center exclusively around such rules.

In the case of the goto statement, it has long been observed that unfettered use of goto's quickly leads to unmaintainable spaghetti code. However, a simple, unthinking ban on the goto statement does not necessarily lead immediately to beautiful programming: an unstructured programmer is just as capable of constructing a Byzantine tangle without using any goto's (perhaps substituting oddly-nested loops and Boolean control variables, instead). Many programmers adopt a moderate stance: goto's are usually to be avoided, but are acceptable in a few well-constrained situations, if necessary: as multi-level break statements, to coalesce common actions inside a switch statement, or to centralize cleanup tasks in a function with several error returns.

Most observations or ``rules'' about programming style (Structured Programming is Good, goto's are Bad, functions should fit on one page, etc.) usually work better as guidelines than rules, and work much better if programmers understand what the guidelines are trying to accomplish. Blindly avoiding certain constructs or following rules without understanding them can lead to just as many problems as the rules were supposed to avert.

Furthermore, many opinions on programming style are just that: opinions. They may be strongly argued and strongly felt, they may be backed up by solid-seeming evidence and arguments, but the opposing opinions may be just as strongly felt, supported, and argued. It's usually futile to get dragged into ``style wars,'' because on certain issues (such as those referred to in questions 5.3, 5.9, 9.4, and 10.7), opponents can never seem to agree, or agree to disagree, or stop arguing.

Finally, as William Strunk has written (quoted in the Introduction to Strunk and White's classic Elements of Style),

It is an old observation that the best writers sometimes disregard the rules of rhetoric. When they do, however, the reader will usually find in the sentence some compensating merit, attained at the cost of the violation. Unless he is certain of doing as well, he will probably do best to follow the rules.

References: K&R2 Sec. 3.8
E. Dijkstra, ``Go To Statement Considered Harmful''
D.E. Knuth, ``Structured Programming with goto Statements''

comp.lang.c FAQ list · Question 17.11

Q: People always say that good style is important, but when they go out of their way to use clear techniques and make their programs readable, they seem to end up with less efficient programs. Since efficiency is so important, isn't it necessary to sacrifice some style and readability?

A: It's true that grossly inefficient programs are a problem, but the blind zeal with which many programmers often chase efficiency is also a problem. Cumbersome, obscure programming tricks not only destroy readability and maintainability, but they may actually lead to slimmer long-term efficiency improvements than would more appropriate design or algorithm choices. With care, it is possible to design code which is both clean and efficient.

See also question 20.13.

comp.lang.c FAQ list · Question 17.12

Q: Which is correct,

char *p
char* p

A: In this case, it's a question of style, not correctness, but see question 1.5.

Additional links: further reading

Read sequentially: prev next up

about this FAQ list   about eskimo   search   feedback   copyright

Hosted by Eskimo North