I know C99 allows declarations to be mixed with code and not only at the beginning, but I'm trying to find where in ISO/IEC 9899:1999 it is written - could you point me to the section(s) I should search?
Thanks in advance.
The change is mentioned in the (non-normative) Forward, page xii, as "mixed declarations and code". (IMHO, declarations are "code"; it should have said "mixed declarations and statements".)
It's defined in the grammar for a compound-statement in 6.8.2:
compound-statement:
{ block-item-list[opt] }
block-item-list:
block-item
block-item-list block-item
block-item:
declaration
statement
The corresponding grammar in the C89/C90 standard was:
compound-statement:
{ declaration-list[opt] statement-list[opt] }
declaration-list:
declaration
declaration-list declaration
statement-list:
statement
statement-list statement
The answer is in clause 6.8.2:
block-item: declaration
statement
A block-item can be either a statement or a declaration, without them needing to be in a particular order:
compound-statement:
{ block-item-list_opt }
block-item-list: block-item
block-item-list block-item
C 1999 6.8.2 two says a compound-statement is “{”, an optional block-item-list, and a “}”, and that a block-item-list is either a block =-item or another block-item-list and a block-item, and that a block-item is a declaration or a statement. Therefore, a declaration can be any of the block-items in a compound-statement. In turn, 6.8 says a compound-statement can appear anywhere a statement can appear. Additionally, 6.9.1 says the body of a function-definition is a compound-statement.
compound-statement:
{ block-item-list[opt] }
block-item-list:
block-item
block-item-list block-item
block-item:
declaration
statement
Related
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.
I know that f(void) { return 0; } has an return type of int, even though it isn't specified, but what about the following:
(*f())[]{}
(*g())(){}
const*h(){}
This compiled with no errors on gcc with -ansi -Werror -pedantic and only complained about the missing return statement in clang: https://godbolt.org/z/jAYL4v
f seems to have a return type of int(*)[], g seems to have a return type of int(*)(), and h seems to have a return type of const int*.
In the ANSI C standard, I can't seem to find the rule for this. I checked [6.5.4.3 Function declarators (including prototypes)] and [6.7.1 Function definitions], but couldn't even find anything on the implicit int return type (except in some example code). Am I just looking in the wrong place? Is this valid code?
The grammar for Function Definitions (C89 3.7.1) is:
function-definition:
declaration-specifiersopt declarator declaration-listopt compound-statement
which is the same as C99 except that the declaration-specifiers are optional in C89.
The meanings of those grammar terms are:
declaration-specifiers is any combination of storage-class-specifier, type-specifier, and type-qualifier; examples of which are static, float, const respectively.
declarator, informally, is anything that could appear here: int ______ ; . There is a formal definition of it of course but I mention this approach so you can relate the terminology to your existing understanding of declaration syntax.
declaration-list refers to K&R-style parameter declarations.
compound-statement is a braced list of statements (possibly empty).
In your question, the following are declarators: (*f())[] (*g())() *h() . So it is legal to have them followed by {} (which is compound-statement). The h also has a declaration-specifier.
In C89 there's also a rule (3.5.2) that providing no type-specifier in a set of declaration-specifiers is equivalent to providing int. C99 added a constraint "At least one type specifier shall be given in the declaration specifiers in each declaration [...]".
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?
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.
Is the following legal C89?
void f(a)
char a[sizeof &f];
{
}
My thinking is yes, since the scope of an identifier declared outside any block scope starts immediately after the end of the declarator and extends to the end of the translation unit. Hence the scope of 'f' includes the declaration-list.
"gcc -pedantic -Wall" accepts it.
"clang -pedantic -Wall" rejects it, as does lcc.
From the C90 Standard (emphasis mine)
(C90, 6.1.2.1) "Structure, union, and enumeration tags have scope that begins just after the appearance of the tag in a type specifier that declares the tag. Each enumeration constant has scope that begins just after the appearance of its defining enumerator in an enumerator list. Any other identifier has scope that begins just after the completion of its declarator."
So for me also, it's a valid function declaration.
EDIT: Devil is in the details (the word completion) and after second thought I think that it is not a valid function declaration as the declarator is not complete after void f(a).
void f(a)
char a[sizeof &f];
^
^ here marks where the declarator is complete and where f scope begins.