I did not understand why this works:
if(1)
{
int i;
}
and this not:
if(1)
int i;
error: expected expression before int
If you could supply some standard reference.
In C, declarations can only occur as part of a compound-statement, not as part of any of the other kinds of statement (see C11 6.8 and 6.8.2).
This is due to C grammar. Specifically, the if statement is defined as:
if ( expression ) statement
According to C11 6.8 Statements and blocks, the statement is one of:
labeled-statementcompound-statementexpression-statementselection-statementiteration-statementjump-statement
The declaration can only directly appear in either compound-statement (i.e. delimeted by { ... }) or as a special case as first expression in for iteration-statement.
Declaration must be a part of a block-item1.
The block-item-list contains a block-item2.
And the block-item-list can only be inside brackets, as part of a compound-statement3.
This is different in C++, as a declaration-statement is included in statement (the former allows, via a block-statement, defining variables).
(Quoted from ISO/IEC 9899:201x 6.8.2 Compound statement 1)
1
block-item:
declaration
2
block-item-list:
block-item
block-item-list block-item
3
compound-statement:
{ block-item-list opt }
As you can see from section 6.8.2p1 which covers the { ... }-style example, a declaration is permitted within a compound-statement.
Section 6.8.4p1, however, which covers the syntax for selection statements (i.e. if (...) ...) doesn't explicitly permit any declarations. In addition, this notation requires an expression, as hinted by the error message, "expected expression ..."
The first code example declares an int visible only inside an otherwise empty scope ... hard to see the utility! The second apparently attempts to conditionally? declare an int visible in the enclosing (function?) scope. Hard to imagine the utility of such a conditional declaration ... would it require run-time re-compilation?
Related
If I do:
int j = ({int x = 7; x+3;});
In i686-apple-darwin10-gcc-4.2.1 (GCC) 4.2.1 (Apple Inc. build 5646) gcc it compiles just fine. The block in question ({int x = 7; x+3;}) returns the value of the last statement as the value of the block. If you remove the parenthesis it doesn't compile. Can I expect this to work in most C compilers?
Additionally, what is the name for this construct? I have had a lot of trouble searching for it because search engines don't index () or {} and C is a terrible search term. I also haven't been able to find anything about it in any of my books, probably because I don't know what to look for.
It's a GCC extension:
A compound statement enclosed in parentheses may appear as an expression in GNU C. This allows you to use loops, switches, and local variables within an expression.
Recall that a compound statement is a sequence of statements surrounded by braces; in this construct, parentheses go around the braces. For example:
({ int y = foo (); int z;
if (y > 0) z = y;
else z = - y;
z; })
is a valid (though slightly more complex than necessary) expression for the absolute value of foo ().
The last thing in the compound statement should be an expression followed by a semicolon; the value of this subexpression serves as the value of the entire construct. (If you use some other kind of statement last within the braces, the construct has type void, and thus effectively no value.)...
If you remove the parenthesis it doesn't compile.
Without the parentheses, the compiler will treat this as an aggregate initialization block and will fail when it sees the int keyword. You cannot have keywords in initializer blocks.
6.7.8 Initialization
11 The initializer for a scalar shall be a single expression, optionally enclosed in braces. The
initial value of the object is that of the expression (after conversion); the same type
constraints and conversions as for simple assignment apply, taking the type of the scalar
to be the unqualified version of its declared type.
6.2.5 Types
21 Arithmetic types and pointer types are collectively called scalar types. Array and
structure types are collectively called aggregate types.
Can I expect this to work in most c compilers?
No. Looks like a non-standard GNU extension.
Additionally, what is the name for this construct?
I wonder if there is any. Actually, this is similar to what macros typically do.
You can expect it to work in most versions of GCC.
You can expect it to work almost nowhere else - it is a GCC extension.
The section of the GCC manual that describes the feature is titled 'Statements and Declarations in Expressions':
A compound statement enclosed in parentheses may appear as an expression in GNU C.
Later it says:
Any temporaries created within a statement within a statement expression will be destroyed
at the statement’s end. This makes statement expressions inside macros slightly
different from function calls.
So, 'statement expression' seems to be the name used in the documentation.
In the C11 standard
6.8 Statements and blocks
A block allows a set of declarations and statements to be grouped
into one syntactic unit.
6.8.2 Compound statement Syntax
compound-statement:
{ block-item-listopt }
block-item-list:
block-item
block-item-list block-item
block-item:
declaration
statement
Semantics
A compound statement is a block.
6.9.1 Function definitions
Syntax
function-definition:
declaration-specifiers declarator declaration-listopt compound-statement
So a compound statement is a block.
Is a block a compound statement?
In a function definition, does the part "compound-statement" mean the same as a block?
A compound-statement is a block, but it's not the only thing which is a block. An iteration statement is also a block, for example (6.8.5/5), even if the loop body consists of a simple statement.
The syntax of a function definition, unlike an iteration statement, requires braces. A compound-statement is a syntactic category which is surrounded by braces.
A block is a semantic category, used to specify the scope of names and the lifetime of automatic objects.
In C11 standard ( I don't have the latest standard):
6.8 Statements and blocks
A block allows a set of declarations and statements to be grouped into one syntactic unit.
The initializers of objects that have automatic storage duration, and the variable length
array declarators of ordinary identifiers with block scope, are evaluated and the values are
stored in the objects (including storing an indeterminate value in objects without an
initializer) each time the declaration is reached in the order of execution, as if it were a
statement, and within each declaration in the order that declarators appear.
Is a block a statement?
Simply put, yes. In its simplest interpretation, if we look at the grammar production before your quote. The most obvious block is a compound statement.
statement:
labeled-statement
compound-statement
expression-statement
selection-statement
iteration-statement
jump-statement
The production of compound-statement describes blocks. And even says this explicitly in a paragraph following that
6.8.2 Compound statement
compound-statement:
{ block-item-list }
block-item-list:
block-item
block-item-list block-item
block-item:
declaration
statement
2 A compound statement is a block.
And other statements in the following sections are also designated as blocks. For instance
6.8.4 Selection statements
3 A selection statement is a block whose scope is a strict subset of
the scope of its enclosing block. Each associated substatement is also
a block whose scope is a strict subset of the scope of the selection
statement.
Nothing except the statements described in 6.8 is ever called a block. So blocks are always a statement of some sort. The rule of thumb is that a statement with { } always means a block.
From wikibooks,
A block is a program region containing definitions of variables and that delimits the regions where these definitions apply. In C programming language, a block is created using a pair of curly braces. The beginning of the block is denoted by an open curly brace '{' and the end is denoted by a closing curly brace '}'. The block collects statements together into a single compound statements.
The C code bellow shows a block where the block is used only to define a scope of a variable and it is not a statement.
#include <stdio.h>
int main() {
int n = 1;
{
int n = 2;
printf("%d\n", n);
}
printf("%d\n", n);
}
EDIT:
As already mentioned I have made a mistake saying that block is not always a statement but the correct answer is that block is ALWAYS a statement.
So this in C99:
label:
int ret = function(of, stuff);
gives a compile-time error, whereas this:
label:
;
int ret = function(of, stuff);
works just fine.
Is this a compiler bug? Or is this a bug in the definition of the C standard? Or if this is part of the C99 standard, perhaps someone would rise to the defense of the C standard to claim that this makes perfect sense?
Labels, which are defined in N1256 6.8.1 Labeled statements, can only contain statements.
Syntax
1 labeled-statement:
identifier : statement
case constant-expression : statement
default : statement
int ret = function(of, stuff); is an declaration, which is defined in N1256 6.7 Declarations and isn't a statement.
Statements are defined below in N1256 6.8 Statements and blocks:
Syntax
1 statement:
labeled-statement
compound-statement
expression-statement
selection-statement
iteration-statement
jump-statement
compound-statement is so-called blocks, which is 0 or more declarations and statements surrounded by {}.
expression-statement is zero or one expression defined in N1256 6.5 Expressions, followed by a semicolon like i++;. The expression in the syntax is defined in N1256 6.5.17 Comma operator.
selection-statement is if and switch statement.
iteration-statement is while, do-while and for statement.
jump-statement is goto, continue, break and return statement.
As you see, declarations are not a statement, so you cannot put labels to declarations.
Arguably a bug in the spec -- when it was changed to allow statements and declarations to be mixed in a block (rather than requiring all declarations before statements), it should also have been changed to allow labels on a declaration, but it was not. An artifact of how the language evolved over time.
Its not a major problem as you discovered, as you can work around it trivially by putting the label on an empty statement before the declaration.
If I do:
int j = ({int x = 7; x+3;});
In i686-apple-darwin10-gcc-4.2.1 (GCC) 4.2.1 (Apple Inc. build 5646) gcc it compiles just fine. The block in question ({int x = 7; x+3;}) returns the value of the last statement as the value of the block. If you remove the parenthesis it doesn't compile. Can I expect this to work in most C compilers?
Additionally, what is the name for this construct? I have had a lot of trouble searching for it because search engines don't index () or {} and C is a terrible search term. I also haven't been able to find anything about it in any of my books, probably because I don't know what to look for.
It's a GCC extension:
A compound statement enclosed in parentheses may appear as an expression in GNU C. This allows you to use loops, switches, and local variables within an expression.
Recall that a compound statement is a sequence of statements surrounded by braces; in this construct, parentheses go around the braces. For example:
({ int y = foo (); int z;
if (y > 0) z = y;
else z = - y;
z; })
is a valid (though slightly more complex than necessary) expression for the absolute value of foo ().
The last thing in the compound statement should be an expression followed by a semicolon; the value of this subexpression serves as the value of the entire construct. (If you use some other kind of statement last within the braces, the construct has type void, and thus effectively no value.)...
If you remove the parenthesis it doesn't compile.
Without the parentheses, the compiler will treat this as an aggregate initialization block and will fail when it sees the int keyword. You cannot have keywords in initializer blocks.
6.7.8 Initialization
11 The initializer for a scalar shall be a single expression, optionally enclosed in braces. The
initial value of the object is that of the expression (after conversion); the same type
constraints and conversions as for simple assignment apply, taking the type of the scalar
to be the unqualified version of its declared type.
6.2.5 Types
21 Arithmetic types and pointer types are collectively called scalar types. Array and
structure types are collectively called aggregate types.
Can I expect this to work in most c compilers?
No. Looks like a non-standard GNU extension.
Additionally, what is the name for this construct?
I wonder if there is any. Actually, this is similar to what macros typically do.
You can expect it to work in most versions of GCC.
You can expect it to work almost nowhere else - it is a GCC extension.
The section of the GCC manual that describes the feature is titled 'Statements and Declarations in Expressions':
A compound statement enclosed in parentheses may appear as an expression in GNU C.
Later it says:
Any temporaries created within a statement within a statement expression will be destroyed
at the statement’s end. This makes statement expressions inside macros slightly
different from function calls.
So, 'statement expression' seems to be the name used in the documentation.