I'm reading an introducty book about C and I came across the following paragraph:
But the following code compiles with expected output:
#include <stdio.h>
int main()
{
for(int i = 0; i<=10; i++)
{
int val = i + 1;
int x = val * val;
printf("%d\n", x);
int y = x;
}
return 0;
}
I use https://www.onlinegdb.com/ and in the above code I declared many variables after the first executable statement. And this is to me does not match what the section from the book tells.
Am I misunderstanding what the book is telling?
In strictly conforming C 1990, declarations could appear only at file scope (outside of function definitions) or at the start of a compound statement. The grammar for a compound statement in C 1990 6.6.2 was:
compound-statement
{ declaration-listopt statement-listopt }
That says a compound statement is { followed by zero or more declarations, then zero or more statements, then }. So the declarations had to come first.
In C 1999 6.8.2, this changed to:
compound-statement
{ block-item-listopt }
A block-item-list is a list of block-item, each of which may be a declaration or a statement, so declarations and statements could be freely mixed.
In your example, the declarations int val = i + 1; and int x = val * val; do not appear after executable statements in their compound statement. The compound statement starts with the { immediately before int val = i + 1;, so that declaration is at the start of the compound statement.
Another change was that the for grammar was changed from this in C 1990 6.6.5:
for ( expressionopt ; expressionopt ; expressionopt ) statement
to this choice of two forms in C 1999 6.8.5:
for ( expressionopt ; expressionopt ; expressionopt ) statement
for ( declaration expressionopt ; expressionopt ) statement
(Note the declaration includes a terminating ;.)
That explains why you can have int i = 0 in for(int i = 0; i<=10; i++).
The book is referring to the original C specification from over 30 years ago known as "ANSI C" or "C89" or "C90". If we run a C compiler in C89 mode, -std=c89, we get a warning from your code...
cc -Wall -Wshadow -Wwrite-strings -Wextra -Wconversion -std=c89 -pedantic -g -fsanitize=address -c -o test.o test.c
test.c:5:9: warning: variable declaration in for loop is a C99-specific feature [-Wc99-extensions]
for(int i = 0; i<=10; i++)
^
test.c:5:9: warning: GCC does not allow variable declarations in for loop initializers before C99 [-Wgcc-compat]
2 warnings generated.
C99, the update to C made in 1999, made this untrue. Running your code with -std=c99 gives no warning. C99 made this and other impactful changes to the language, like // comments.
There is also C11 and the latest stable version of C is C17, but compiler support for both is spotty.
Why is this book referring to such an old version of the language? C has existed since 1978 and there are a lot of old code and old compilers out there. C Compilers have been very slow to fully adopt new standards making authors quite conservative. A big stumbling block was Microsoft Visual C++ did not implement C99 until 2013! So ANSI C was the lowest-common denominator for a very long time.
In recent years, C compilers have gotten better about standards compliance, so you can rely on C99 (which is old enough to drink) as your baseline.
All variables in your example have been declared before used.
The declarations are:
int i ...;
int val ...;
int x ...;
Note that all declarations happen before the first function call in the corresponding block. On other words: i, val and x are all declared before the printf.
As stated in the comments: Some old books might refer to old versions of C. The variable declaration within the for loop came with C99 for example. Beginning with C99 you could also declare variables in the middle of the block. So you are allowed to declare some int y; after the printf and your code would still compile.
Related
Wiki says:
The extern keyword means "declare without defining". In other words, it is a way to explicitly declare a variable, or to force a declaration without a definition. It is also possible to explicitly define a variable, i.e. to force a definition. It is done by assigning an initialization value to a variable.
That means, an extern declaration that initializes the variable serves as a definition for that variable. So,
/* Just for testing purpose only */
#include <stdio.h>
extern int y = 0;
int main(){
printf("%d\n", y);
return 0;
}
should be valid (compiled in C++11). But when compiled with options -Wall -Wextra -pedantic -std=c99 in GCC 4.7.2, produces a warning:
[Warning] 'y' initialized and declared 'extern' [enabled by default]
which should not. AFAIK,
extern int y = 0;
is effectively the same as
int i = 0;
What's going wrong here ?
All three versions of the standard — ISO/IEC 9899:1990, ISO/IEC 9899:1999 and ISO/IEC 9899:2011 — contain an example in the section with the title External object definitions (§6.7.2 of C90, and §6.9.2 of C99 and C11) which shows:
EXAMPLE 1
int i1 = 1; // definition, external linkage
static int i2 = 2; // definition, internal linkage
extern int i3 = 3; // definition, external linkage
int i4; // tentative definition, external linkage
static int i5; // tentative definition, internal linkage
The example continues, but the extern int i3 = 3; line clearly shows that the standard indicates that it should be allowed. Note, however, that examples in the standard are technically not 'normative' (see the foreword in the standard); they are not a definitive statement of what is and is not allowed.
That said, most people most of the time do not use extern and an initializer.
This code is perfectly valid.
But any compiler is free to issue additional (informative or not) diagnostics:
(C99, 5.1.1.3p1 fn 8) "Of course, an implementation is free to produce any number of diagnostics as long as a valid program is still correctly translated."
What a compiler cannot do is not emitting a diagnostic when there is a constraint or syntax violation.
EDIT:
As devnull put in the OP question comments, Joseph Myers from gcc team explains in a bug report questioning this diagnostic:
"This is a coding style warning - the code is valid, but extremely
unidiomatic for C since "extern" is generally expected to mean that the
declaration is not providing a definition of the object."
In my code I can't initialize variables in for loop initialization part.
When I write this code:
long unsigned int arr[3][3];
char str[50];
for(;gets(str);)
{
int temp=0;
for(int i,j,k=0; str[k]!='\0'; k++){ if(str[k]!=' ')temp=temp*10+(str[k]-48);
the compiler shows
error: 'for' loop initial declarations are only allowed in c99 mode
I have no idea what that means,
but if I write my code like this:
long unsigned int arr[3][3];
char str[50];
for(;gets(str);)
{
int temp=0;
int i,j,k=0;
for(; str[k]!='\0'; k++){ if(str[k]!=' ')temp=temp*10+(str[k]-48);
it works fine.
Why is this happening?
Declaring variables in loops like
for (int i = 0; ...; ...)
was new in the C99 standard, and wasn't allowed in the earlier standards. What the error message tells you is that your compiler is set up to compile using an earlier standard, and so you can't use declarations inside for statements.
You either have to remove the declaration from inside the for statement, or tell the compiler to use a later standard when compiling. Telling the compiler to use a later version can be done by adding the flag -std=c99 if you have GCC or clang.
You are using a compiler that only supports C89, or the compiler is in the mode that supports C89 only. The declarations of variables must in the beginning of a block in C89. It's not a limit anymore in C99 or C++.
Change to C99 mode or put the declaration of i,j,k in the beginning of the block. The way you initialize them looks incorrect, you only initialized k.
for(;gets(str);)
{
int temp=0;
int i,j,k;
for(i=0,j=0,k=0; str[k]!='\0'; k++){ if(str[k]!=' ')temp=temp*10+(str[k]-48);
And don't use gets, it's dangerous, use fgets instead.
This happens because your former code does not obey the C standard under which you compile the code. Check the manual of your C (or C++) compiler how to turn on (if possible) the compilation under the C99 standard. For GNU compiler it is -std=c99 switch.
I'm using codeblocks to learn C programming.
When I use /* */ the program works, but when I use // the program returns this error.
expected identifier or ‘(’ before ‘/’ token|
here's the main.c
#include <stdio.h>
#include <stdlib.h>
//Ex1
int i;
float p;
char *n;
int main(void)
{
i = 22;
p = 70.0;
n = "Samuel";
printf("%s %d %.2f", n, i, p);
return 0;
}
From wiki:
C++ style line comments start with // and extend to the end of the line. This style of comment originated in BCPL and became valid C syntax in C99; it is not available in the original K&R C nor in ANSI C:
If you use gcc compiler, then add -std=c99 compiler argument.
It will enables C99 features, like // comments.
If you have -ansi option, then remove it.
Four major versions of the C language exist:
ISO 9899:2011. The current standard, known as C11. Allows //.
ISO 9899:1999. An obsolete standard, known as C99. Allows //.
ISO 9899:1990. An obsolete standard, known as C90, or sometimes C89. Does not allow //.
Pre-standardization. Known as "K&R C". Does not allow //.
Make sure to use a modern compiler with support for the relevant standard. Today, you should demand that a C compiler at least conforms with C99.
I was trying to do this in ANSI C:
include <stdio.h>
int main()
{
printf("%d", 22);
int j = 0;
return 0;
}
This does not work in Microsoft Visual C++ 2010 (in an ANSI C project). You get an error:
error C2143: syntax error : missing ';' before 'type'
This does work:
include <stdio.h>
int main()
{
int j = 0;
printf("%d", 22);
return 0;
}
Now I read at many places that you have to declare variables in the beginning of the code block the variables exist in. Is this generally true for ANSI C89?
I found a lot of forums where people give this advice, but I did not see it written in any 'official' source like the GNU C manual.
ANSI C89 requires variables to be declared at the beginning of a scope. This gets relaxed in C99.
This is clear with gcc when you use the -pedantic flag, which enforces the standard rules more closely (since it defaults to C89 mode).
Note though, that this is valid C89 code:
include <stdio.h>
int main()
{
int i = 22;
printf("%d\n", i);
{
int j = 42;
printf("%d\n", j);
}
return 0;
}
But use of braces to denote a scope (and thus the lifetime of the variables in that scope) doesn't seem to be particularly popular, thus C99 ... etc.
Now I read at many places that you have to declare variables in the beginning of the code block the variables exist in. Is this generally true for ANSI C 89?
Yes, this is required in the syntax of a compound statement in the C89/C90 Standard:
(C90, 6.6.2 Compound statement, or block)
Syntax
compound-statement
{ declaration-list_opt statement-list_opt }
Declaration have to be before statements in a block.
C99 relaxed this by allowing mixing of declarations and statements in a block. In the C99 Standard:
(C99, 6.8.2 Compound statement)
Syntax
compound-statement:
{ block-item-list_opt }
block-item-list:
block-item
block-item-list block-item
block-item:
declaration
statement
This is absolutely true for C89. (You're better off looking at documentation for the language, e.g., books and standards. Compiler documentation usually only documents differences between the language the compiler supports and ANSI C.)
However, many "C89" compilers allow you to put variable declarations nearly anywhere in a block, unless the compiler is put in a strict mode. This includes GCC, which can be put into a strict mode with -pedantic. Clang defaults to a C99 target, so -pedantic won't affect whether you can mix variable declarations with code.
MSVC has rather poor support for C, I'm afraid. It only supports C89 (old!) with a few extensions.
Can someone elaborate on the following gcc error?
$ gcc -o Ctutorial/temptable.out temptable.c
temptable.c: In function ‘main’:
temptable.c:5: error: ‘for’ loop initial declaration used outside C99 mode
temptable.c:
...
/* print Fahrenheit-Celsius Table */
main()
{
for(int i = 0; i <= 300; i += 20)
{
printf("F=%d C=%d\n",i, (i-32) / 9);
}
}
P.S: I vaguely recall that int i should be declared before a for loop. I should state that I am looking for an answer that gives a historical context of C standard.
for (int i = 0; ...)
is a syntax that was introduced in C99. In order to use it you must enable C99 mode by passing -std=c99 (or some later standard) to GCC. The C89 version is:
int i;
for (i = 0; ...)
EDIT
Historically, the C language always forced programmers to declare all the variables at the begin of a block. So something like:
{
printf("%d", 42);
int c = 43; /* <--- compile time error */
must be rewritten as:
{
int c = 43;
printf("%d", 42);
a block is defined as:
block := '{' declarations statements '}'
C99, C++, C#, and Java allow declaration of variables anywhere in a block.
The real reason (guessing) is about allocating internal structures (like calculating stack size) ASAP while parsing the C source, without go for another compiler pass.
Before C99, you had to define the local variables at the start of a block. C99 imported the C++ feature that you can intermix local variable definitions with the instructions and you can define variables in the for and while control expressions.