When I tried the following code I get the error mentioned.
if(a==1)
int b =10;
But the following is syntactically correct
if(a==1)
{
int b = 10;
}
Why is this?
This is actually a fairly interesting question. It's not as simple as it looks at first. For reference, I'm going to be basing this off of the latest C11 language grammar defined in N1570
I guess the counter-intuitive part of the question is: if this is correct C:
if (a == 1) {
int b = 10;
}
then why is this not also correct C?
if (a == 1)
int b = 10;
I mean, a one-line conditional if statement should be fine either with or without braces, right?
The answer lies in the grammar of the if statement, as defined by the C standard. The relevant parts of the grammar I've quoted below. Succinctly: the int b = 10 line is a declaration, not a statement, and the grammar for the if statement requires a statement after the conditional that it's testing. But if you enclose the declaration in braces, it becomes a statement and everything's well.
And just for the sake of answering the question completely -- this has nothing to do with scope. The b variable that exists inside that scope will be inaccessible from outside of it, but the program is still syntactically correct. Strictly speaking, the compiler shouldn't throw an error on it. Of course, you should be building with -Wall -Werror anyways ;-)
(6.7) declaration:
declaration-specifiers init-declarator-listopt ;
static_assert-declaration
(6.7) init-declarator-list:
init-declarator
init-declarator-list , init-declarator
(6.7) init-declarator:
declarator
declarator = initializer
(6.8) statement:
labeled-statement
compound-statement
expression-statement
selection-statement
iteration-statement
jump-statement
(6.8.2) compound-statement:
{ block-item-listopt }
(6.8.4) selection-statement:
if ( expression ) statement
if ( expression ) statement else statement
switch ( expression ) statement
{ } -->
defines scope, so if(a==1) { int b = 10; } says, you are defining int b, for {}- this scope. For
if(a==1)
int b =10;
there is no scope. And you will not be able to use b anywhere.
By C89, variable can only be defined at the top of a block.
if (a == 1)
int b = 10; // it's just a statement, syntacitially error
if (a == 1)
{ // refer to the beginning of a local block
int b = 10; // at the top of the local block, syntacitially correct
} // refer to the end of a local block
if (a == 1)
{
func();
int b = 10; // not at the top of the local block, syntacitially error, I guess
}
Related
So I solved my problem, wasn't that hard, but I'm wandering why the first version wasn't working.
So here, an example of my problem :
typedef struct a {
int i;
} A;
typedef struct b {
int i;
A a;
} B;
typedef B * PB;
PB create_B(int ia, int ib) {
PB b = malloc(sizeof(B));
b->i = ib;
b->a = {ia};
}
I get an error from the compiler saying :
"error: expected expression before ‘{’ token"
at line: b->a = {ia};
But i don't really get what is the problem.
I solved it casting the structure :
PB create_B(int ia, int ib) {
PB b = malloc(sizeof(B));
b->i = ib;
b->a = (A){ia};
}
But the types are well defined no ? I mean it's kind of obvious to me that {ia} is of type A since b->a is of type A aswell.
I am probably wrong on this last saying (compiler is probably right). So if you have an example where this situation isn't obvious and really need a cast, it would be really appreciated, or jut an explanation at least.
Thank you for your time.
Barioth
PS :
I could have done that too i guess
PB create_B(int ia, int ib) {
PB b = malloc(sizeof(B));
*b = (B){ib, {ia}};
}
But i still need a cast...
{ia} is not an expression in C and cannot be used in an expression statement.
{ia} is part of a syntax for definitions. In a definition, a list of initial values may be given in braces after an =. (And the braces may be omitted when initializing a scalar object.) This is a special syntax for initializing in a definition and is not an assignment like using = in an expression.
(A){ia} is an expression; it is a construct called a compound literal. After a type name in parentheses, initial values are given inside braces. This creates an object of the stated type. That object may then be used in an expression, such as as the right operand of an assignment.
Is creating local scopes with just a pair of brackets, would that be considered standard C?
#include <stdio.h>
int main(int argc, char *argv[]) {
{
register char x = 'a';
putchar(x); // works
}
//putchar(x); wont work
}
Or is it best to not use this? Is it a GCC compiler extension?
I have once been told that the accepted practice is a do {...} while (0); loop. Is it true that all C compilers will recognise this practice just like it is safe to assume any given C compiler will recognise an if statement?
I tried googling this, and my results were about scope behavior, and had nothing to do with manually applying scopes.
Yes, it is standard; this is creation of block scope, as supported by C language.
Regarding "best to use" part, it depends, certainly it might be a bit confusing to some people.
This might come in very useful with generated code though, so you don't need to bother (as much) with unique identifiers for local vars:
int main(int argc, char *argv[]) {
{
int x = 4;
printf("%d\n", x);
}
{
int x = 5;
printf("%d\n", x);
}
}
Yes, it is standard; you can always introduce a new scope with an extra pair of {}
I often use it in conditionally compiled code, to avoid unused variable warnings:
#if DEBUG
{
struct node *tmp;
for (tmp=this; tmp; tmp= tmp->next) {
printf(stderr, "Node %u: %s\n", tmp->num, tmp->name);
}
}
#endif
This is standard C.
Section 6.8p1 of the C standard gives the following syntax for a statement:
statement:
labeled-statement
compound-statement
expression-statement
selection-statement
iteration-statement
jump-statement
Where a compound-statement is defined in section 6.8.2p1:
compound-statement:
{ block-item-list(opt) }
block-item-list:
block-item
block-item-list block-item
block-item:
declaration
statement
What this says is that anyplace that a statement can occur, a compound statement (i.e. a set of statements surrounded by {}) can occur.
I'm writing a C compiler, and when I come to the implementation of the switch statement one constraint confused me a lot. Section 6.8.4.2p2 of the standard states:
If a switch statement has an associated case or default label within
the scope of an identifier with a variably modified type, the entire
switch statement shall be within the scope of that identifier.
With a footnote:
That is, the declaration either precedes the switch statement, or it
follows the last case or default label associated with the switch that
is in the block containing the declaration.
I can't really understand what this constraint means. Can some one give me an example?
I think that this quote from the C Standard relative to the goto statement will help to understand the quote relative to the switch statement.
6.8.6.1 The goto statement
1 The identifier in a goto statement shall name a label located
somewhere in the enclosing function. A goto statement shall not jump
from outside the scope of an identifier having a variably modified
type to inside the scope of that identifier.
In fact the swutch statement uses goto statements to pass the control to the selected label. So any such passing the control to a case label shall not skip a declaration of an object of a variable modified type. That is such a declaration either should be placed before a swict statement or inside the switch statement after all its labels.
And there is an example
goto lab3; // invalid: going INTO scope of VLA.
{
double a[n];
a[j] = 4.4;
lab3:
a[j] = 3.3;
goto lab4; // valid: going WITHIN scope of VLA.
a[j] = 5.5;
lab4:
a[j] = 6.6;
}
goto lab4; // invalid: going INTO scope of VLA.
that is the statements goto lab3; and goto lab4; are bypassing the declaraion double a[n];.
Here is an example of a valid switch statement according to the footnote.
#include <stdio.h>
int main(void)
{
int n = 2;
switch ( n )
{
case 0:
break;
case 1:
break;
default: ;
int a[n];
for ( int i = 0; i < n; i++ ) a[i] = i;
int sum = 0;
for ( int i = 0; i < n; i++ ) sum += a[i];
printf( "sum = %d\n", sum );
}
return 0;
}
The program output is
sum = 1
What this is saying is that if one case is able to see a variably modified array, then the entire switch statement MUST be able to see it as well.
This means that the following code is legal:
void switch_test(int size)
{
int array[size];
...
// code to populate array
...
switch (expr) {
case 1:
printf("%d\n", array[0]);
break;
case 2:
// do something else
}
}
But this code is not:
void switch_test(int size)
{
switch (expr) {
case 2:
// do something else
int array[size]; // ILLEGAL, VLA in scope of one label but not all
case 1:
...
// code to populate array
...
printf("%d\n", array[0]);
}
}
The reason the latter is illegal is because if the code were to jump to case 1 then array might not have been created properly since the size of a VLA is determined at run time. Ensuring that the VLA is visible before the switch statement avoids this issue.
If a switch statement has an associated case or default label within the scope of an identifier with a variably modified type, the entire switch statement shall be within the scope of that identifier.
void func(int a) {
switch(a) {
{ // this is the scope of variable b
// b is an identifier with variably modified type
int b[a];
// the following is the "associated case within a scope of an identifier"
case 1: // this is invalid
break;
}
// the scope of switch statement has to be within the scope of that identifier
}
}
It is so because compiler may need to emit cleanup instructions after allocating memory for VLA variable. In switch you can jump anywhere in the code, so instructions for allocating or cleaning the memory for a variable length array could be omitted.
Consider this simple program:
fails.c:
#include <stdio.h>
int main(){
int i = 10;
if (i == 10)
int j = 11;
return 0;
}
That fails to compile (gcc fails.c), giving this error:
fails.c: In function ‘main’:
fails.c:7:3: error: expected expression before ‘int’
int j = 11;
^
But this one goes through just fine:
#include <stdio.h>
int main(){
int i = 10;
if (i == 10){
int j = 11;
}
return 0;
}
I figured that the work around, is to put those {} in. But I wish to know why this is required.
Why does it behave this way, when something like printf is acceptable?
#include <stdio.h>
int main(){
int i = 10;
if (i == 10)
printf("some text\n");
return 0;
}
This is because if must be followed by a statement:
C99/6.8.4
if ( expression ) statement
However, a declaration is not a statement:
C99/6.8
statement:
labeled-statement
compound-statement
expression-statement
selection-statement
iteration-statement
jump-statement
When put inside a {}, it is a compound-statement, thus ok.
There is a difference between declaration and statement.
int j = 11;
is a declaration. if statement shall be followed by a statement. Putting {} after if statement results in a compound statement. A compound statement can have no other statement in it or can have a declaration.
It seems you compile your ANSI C code with C89 standard. And, unlike his successor C99, it requires all variables to be declared at the beginning of the scope. So, having int j = 11; somewhere in-between other statements just contradicts that C89 rule. If you open a new scope just before that int j = 11;, it's back to OK.
Actual reason of such C89 limitation should be an attempt to simplify memory management for stack-allocable variables. For instance, compare it with Pascal language that requires all variables to be declared in the special var section before the code (so, it's even more strict that C89).
Bad style notwithstanding, is it legal C to have a for loop with braces inside the parens? Like this:
char *a = "a ";
char *b = "b ";
for ( { int aComesFirst = 1;
char *first = a;
char *second = b;
};
aComesFirst >= 0;
{ aComesFirst--;
swap(first, second);
} )
{
printf("%s%s\n", first, second);
}
If something along those lines is possible, am I supposed to put a semicolon after the first close braces, or would that add an empty statement?
I do realize that it is stylistically better to move the char* declarations outside the for loop and the swap to the end of the inside of the loop. But style is not the point of this question, I just want to know if putting braces inside the parens is possible.
I've answered this before… this can easily be made legal in C or C++ by adding a local struct type. It's generally poor style, though.
char *a = "a ";
char *b = "b ";
for ( struct loopy {
int aComesFirst;
char *first;
char *second;
} l = { 1, a, b }; /* define, initialize structure object */
l.aComesFirst >= 0; /* loop condition */
l.aComesFirst--, /* loop advance */
swap(l.first, l.second)
)
{
printf("%s%s\n", l.first, l.second);
}
No, it's not legal, but you can use commas to get half way there:
for (int a = 1, b = 2; a < 10; ++a, ++b)
You can't declare multiple variables of different types, and you can't use control structures in the last bit, but it's good enough most of the time.
If you didn't know, the comma used there is not some special syntax that can only be used in for loops, it's a general operator that can be used anywhere to evaluate the left operand, followed by the right operand, and return the result of the right expression, i.e. a, b == b, and a, b, c == c and so on.
No, it is not legal. If it was legal the code wouldn't work anyway because c has block level scope, so you wouldn't have access to an of the variables defined in the braces.
That's not legal but this is:
for(i = 0, j = 10; i < 10; i++, j--)
{
// ..
}
See: the comma operator
Are you using the gcc with Statement Expressions? http://tigcc.ticalc.org/doc/gnuexts.html#SEC63
Maybe that will make that type of code work. except it's (int i = { stmts; }; { stmts; bool}; { ... })
The Standard says (6.8.5.3/1)
for ( clause-1 ; expr-2 ; expr-3 ) statement
I'm pretty sure neither expr-2 or expr-3 can be replaced by something not an expression (a block is not an expression), and I'm pretty sure clause-1 also cannot be replaced by a statement.