#define FDC_WRITE(reg,val) \

The do statement formally ensures that the code is executed just once when the macro is "called" and does not alter the semantics as compared to a variant without an enclosing do loop. The advantage of this construction becomes clear when the macro is used in if queries or similar language elements as shown here:

if (condition)

At first reading, the code appears to be correct because single-line if bodies can — and in the kernel usually are — used without braces. However, after macro expansion there would be a problem if the enclosing do construction were not present:

if (condition)

Only the first line is included in the if body. The remaining lines are executed regardless of condition and this is not, of course, what was intended. Because structurally the do construction counts as a statement, it ensures that all statements included in the macro are placed within the if body.

Further elements that cause some confusion when reading kernel sources are the C statements break and continue. The following chunks of code can easily be confused:

unsigned int count;

for (count = 0; count < 5; count++) { if (count == 2) { continue;

The code produces the following output when executed:

[email protected]> ./continue count: 0

count: 1

count: 3

count: 4

The third loop pass is exited prematurely because of the continue statement. Nevertheless, the subsequent loop passes are still executed.

If continue is replaced with a break statement as shown in the following code, program behavior is modified:

unsigned int count;

for (count = 0; count < 5; count++) { if (count == 2) { break;

Program output is now as follows:

[email protected]> ./break count: 0 count: 1

Again, the third loop pass is terminated. However, loop processing is not resumed, and the subsequent code is executed. In other words, break completely terminates the loop.

A further stumbling block in C are the semantics of select queries, as the following example shows:

printf("three\n"); default:


The code generates the following output:

[email protected]> ./switch three default

Because the case statement for 3 does not include a break statement, code flow descends to the default label, which under normal circumstances would not have been selected. Generally, switch statements can be exited only by means of break statements (or at the end of the statement itself). Once a suitable statement is found, the code descends until it reaches a corresponding statement — regardless of whether it comes across further labels or not.

Continue reading here: C27 Doubly Linked Lists

Was this article helpful?

0 0