A statement is a complete instruction to the computer. Except as indicated, statements are executed in sequence. Statements have the following form:
statement: | expression-statement compound-statement selection-statement iteration-statement jump-statement labeled-statement |
Most statements are expression statements, which have the following form:
expression-statement: | expressionopt; |
Usually expression statements are expressions evaluated for their side effects, such as assignments or function calls. A special case is the null statement, which consists of only a semicolon.
A compound statement (or block) groups a set of statements into a syntactic unit. The set can have its own declarations and initializers, and has the following form:
compound-statement: | {declaration-listopt statement-listopt} | |
declaration-list: | declaration declaration-list declaration | |
statement-list: | statement statement-list statement |
Declarations within compound statements have block scope. If any of the identifiers in the declaration list were previously declared, the outer declaration is hidden for the duration of the block, after which it resumes its force. In traditional C, however, function declarations always have file scope whenever they appear.
Initialization of identifiers declared within the block is restricted to those that have no linkage. Thus, the initialization of an identifier declared within the block using the extern specifier is not allowed. These initializations are performed only once, prior to the first entry into the block, for identifiers with static storage duration. For identifiers with automatic storage duration, it is performed each time the block is entered at the top. It is currently possible (but a bad practice) to transfer into a block; in that case, no initializations are performed.
Selection statements include if and switch statements and have the following form:
selection-statement: | if (expression) statement if (expression) statement else statement switch (expression) statement |
Selection statements choose one of a set of statements to execute, based on the evaluation of the expression. The expression is referred to as the controlling expression.
The controlling expression of an if statement must have scalar type.
For both forms of the if statement, the first statement is executed if the controlling expression evaluates to nonzero. For the second form, the second statement is executed if the controlling expression evaluates to zero. An else clause that follows multiple sequential else-less if statements is associated with the most recent if statement in the same block (that is, not in an enclosed block).
The controlling expression of a switch statement must have integral type. The statement is typically a compound statement, some of whose constituent statements are labeled case statements (see “Labeled Statements”, and “continue Statement”, respectively).
The following is a simple example of a complete switch statement:
switch (c) { case 'o': oflag = TRUE; break; case 'p': pflag = TRUE; break; case 'r': rflag = TRUE; break; default : (void) fprintf(stderr, "Unknown option\n"); exit(2); } |
Iteration statements execute the attached statement (called the body) repeatedly until the controlling expression evaluates to zero. In the for statement, the second expression is the controlling expression. The format is as follows:
iteration-statement: | while (expression) statement do statement while (expression) ; for (expressionopt ; expressionopt ; expressionopt) statement |
The controlling expression must have scalar type.
The flow of control in an iteration statement can be altered by a jump statement (see “Jump Statements”).
The for statement has the following form:
for (expressionopt ; expressionopt ; expressionopt) | statement |
The first expression specifies initialization for the loop. The second expression is the controlling expression, which is evaluated before each iteration. The third expression often specifies incrementation. It is evaluated after each iteration.
This statement is equivalent to the following:
expression-1; | while (expression-2) { statement expression-3; } |
One exception exists, however. If a continue statement (see “continue Statement” is encountered, expression-3 of the for statement is executed prior to the next iteration.
Any or all of the expressions can be omitted. A missing expression-2 makes the implied while clause equivalent to while. Other missing expressions are simply dropped from the previous expansion.
Jump statements cause unconditional transfer of control. The syntax is as follows:
jump-statement: | goto identifier; continue; break; return expressionopt; |
Control can be transferred unconditionally by means of a goto statement:
goto identifier; |
The identifier must name a label located in the enclosing function. If the label has not yet appeared, it is implicitly declared. (See “Labeled Statements”, for more information.)
The continue statement can appear only in the body of an iteration statement. It causes control to pass to the loop-continuation portion of the smallest enclosing while, do, or for statement; that is, to the end of the loop. Consider each of the following statements:
while (...) { .. contin: ; } do { ... contin: ; } while (...) ; for (...) { ... contin: ; } |
A continue is equivalent to goto contin. Following the contin: is a null statement.
A goto statement must not cause a block to be entered by a jump from outside the block to a labeled statement in the block (or an enclosed block) if that block contains the declaration of a variably modified object or variably modified typedef name.
The break statement can appear only in the body of an iteration statement or code attached to a switch statement. It transfers control to the statement immediately following the smallest enclosing iteration or switch statement, terminating its execution.
A function returns to its caller by means of the return statement. The value of the expression is returned to the caller (after conversion to the declared type of the function), as the value of the function call expression. The return statement cannot have an expression if the type of the current function is void.
If the end of a function is reached before the execution of an explicit return, an implicit return (with no expression) is executed. If the value of the function call expression is used when none is returned, the behavior is undefined.
Labeled statements have the following syntax:
labeled-statement: | identifier : statement case constant-expression : statement default : statement |
A case or default label can appear only on statements that are part of a switch.
Any statement can have a label attached as a simple identifier. The scope of such a label is the current function. Thus, labels must be unique within a function. In traditional C, identifiers used as labels and in object declarations share a name space. Thus, use of an identifier as a label hides any declaration of that identifier in an enclosing scope. In ANSI C, identifiers used as labels are placed in a different name space from all other identifiers and do not conflict. Therefore, the following code fragment is legal in ANSI C but not in traditional C:
{ int foo; foo = 1; ... goto foo; ... foo: ; } |