1: Defining a variable in a header file
If you write:
static int foo = 7;
in a header file, each C source file that includes that header will have a different copy of "foo", each initialized to 7, but each in a different place. These variables will be totally unrelated, even if the intention of the programmer is to have a 353e48d single variable "foo".
If you omit the static, at least you will get an error at link time, and you will see the bug.
Golden rule:
Never define something in a header file. Header files are for declarations only!
2: Confusing = and ==
If you write
if (a = 6)
you are assigning to "a" the number 6, instead of testing for equality. The "if" branch will be always taken because the result of that assignment is different from zero.
3: Forgetting to close a comment
If you write:
a=b; /* this is a bug
c=d; /* c=d will never happen */
The comment in the first line is not terminated. It goes one through the second line and is finished with the end of the second line. Hence, the assignment of the second line will never be executed. Wedit helps you avoid this by coloring commentaries in another color as normal program text.
4: Easily changed block scope.
Suppose you write the following code:
if (someCondition)
fn1();
else
OtherFn();
This is OK, but if you add some code to debug, for instance, you end up with:
if (someCondition)
fn1();
else
printf("Calling OtherFn\n");
OtherFn();
The else is not enclosed in curly braces, so only one statement will be taken. The end result is that the call to OtherFn is always executed, no matter what.
Golden rule:
ALWAYS enclose the scopes of "if" or "else" between curly braces.
5: Using the post-increment or pre-increment operators more than once in an expression. The ANSI C standard[1] specifies that an expression can change the value of a variable only once within an expression. This means that a statement like:
i++ = ++i;
is invalid, as are invalid this, for instance:
i = i+++++i;
(in clear i++ + ++i
6: Unexpected Operator Precedence
The code fragment,
if( chr = getc() != EOF )
will always print 1, as long as end-of-file is not detected in getc. The intention was to assign the value from getc to chr, then to test the value against EOF. The problem occurs in the first line, which says to call the library function getc. The return value from getc (an integer value representing a character, or EOF if end-of-file is detected), is compared against EOF, and if they are not equal (it's not end-of-file), then 1 is assigned to the object chr. Otherwise, they are equal and 0 is assigned to chr. The value of chr is, therefore, always 0 or 1.
The correct way to write this code fragment is,
if( (chr = getc()) != EOF )
The extra parentheses force the assignment to occur first, and then the comparison for equality is done.[2]
7: Extra Semi-colon in Macros
The next code fragment illustrates a common error when using the preprocessor to define constants:
#define MAXVAL 10; // note the semicolon at the end
if( value >= MAXVAL ) break;
The compiler will report an error. The problem is easily spotted when the macro substitution is performed on the above line. Using the definition for MAXVAL, the substituted version reads,
if( value >= 10; ) break;
The semi-colon ( ) in the definition was not treated as an end-of-statement indicator as expected, but was included in the definition of the macro MAXVAL. The substitution then results in a semi-colon being placed in the middle of the controlling expression, which yields the syntax error. Remember: the pre-processor does only a textual substitution of macros.
Paragraph 6.5.2: "Expressions": << Between the previous and the next sequence point an object shall have its stored value modified at most once by the evaluation of an expression. >>. Then, the standards adds in a footnote: "This paragraph renders undefined statement expressions such as:
i = ++i + 1;
a[i++] = i;
|