C: for loop int initial declaration - c

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.

Related

Newbie question about C variable declarations

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.

Error message Variable declaration in C

I'm new to c and I am having a hard time understanding why am I getting an error while trying to compile the following code in c I believe I tried it Java and it worked compiled perfectly without error
void f(void) {
int i;
i = 6;
int j;
j = 20;
}
In "old" C all declarations must be at the top of the functions. In later versions like C99, C declarations can be anywhere in the code. I guess you have an old compiler.
Change your code to
void f(void) {
int i;
int j;
i = 6;
j = 20;
}
The problem is that for some old compilers you need to declare the variables before any executable statement. If you do not want to have this problem, switch to a newer compiler.
If your compiler is configured to compile c code following c98 then you will get this error because following c98 standard the déclaration of variables must be done first then we can make assignment so we can't make declaration of variable in the middle of the code.
However you can select the option to compile your code following the standard c99 and in this case you can make the déclaration of variable in the middle of your code.

Defining the size of an array using a const int

When I try to run this, it gives me an error saying that the value in variable a isn't constant. That doesn't make sense to me because I explicitly made the variable a constant. Does the size of an array have to more constant than that? Meaning, only #define a 5, or initializing it as int arr[5] or using malloc? What is wrong with what I did?
int main{
const int a = 5;
int i;
int arr [a];
for (i = 0; i < 5; i++) {
arr[i] = i * 2;
}
printf("%d", arr[1]);
return 0;
}
In C, const should be read as read-only. It doesn't define a compile time.
const int a = 5;
Here a, is not a constant expression as required by the C standard:
6.7.9 Initialization
4 All the expressions in an initializer for an object that has static or thread storage duration shall be constant
expressions or string literals.
So the error indicates you are using a C89/C90 compiler. You can read the input from user for a and declare a variable length array, which is a C99-feature, which has automatic storage duration.
Using #define is another way. But it's simply a textual replacement and defines an array with automatic storage duration. It's same as defining int arr[5]; yourself.
if you want to allocate memory on dynamic storage (commonly known as "heap"), you have to use malloc() family functions, which will have lifetime thoughout the program execution until you call free() on it.
(Note that this behaviour of const is only in C. C++ differs in this and will work as you expected).
If I compile the code in C89, it fails with:
#include <stdio.h>
int main(){
const int a = 5;
int i;
int arr [a];
for (i = 0; i < 5; i++) {
arr[i] = i * 2;
}
printf("%d", arr[1]);
return 0;
}
$ gcc -Wall -Wextra -std=c89 -pedantic-errors test.c
test.c: In function âmainâ:
test.c:7:4: error: ISO C90 forbids variable length array âarrâ [-Wvla]
int arr [a];
^
because C89 doesn't support VLAs (Although gcc supports it as an extension even in C89/C90). So if you are using a compiler that doesn't support C99 then you can't use VLAs.
For example, visual studio doesn't fully support all C99 and C11 features. Although, Visual studio 2015 support most C99 features, VLAs are not one of them.
But the same code compiles in C99 and C11 without any problem:
$ gcc -Wall -Wextra -std=c99 -pedantic-errors t.c
$ gcc -Wall -Wextra -std=c11 -pedantic-errors t.c
It's because variable length arrays (VLAs) were added in C99. Note that VLAs have been made optional in C11 standard. So an implementation may not support VLAs in C11.
You need to test against __STDC_NO_VLA__ to check if VLAs are not supported by your implementation.
From 6.10.8.3 Conditional feature macros
__STDC_NO_VLA__
The integer constant 1, intended to indicate that the implementation does not support variable length arrays or variably
modified types.
I personally do not use VLAs as the allocation failure can't be portably found if the array size is reasonably large. E.g.
size_t size = 8*1024;
int arr[size];
In the above fragment, if arr allocation failed, you won't know it until runtime. What's a "small enough" size for which the memory allocation is platform dependent. So on one machine, 1MB allocation may succeed and another it may fail and worse part is that there's no way to catch this failure.
Thus the use of VLAs is limited and can only be used with small arrays that you know will always succeed on a given platform. But in that I would simply hard-code the array size and take care of the boundary conditions.
Maybe use an enum to define the value of a.
enum { a = 5 };
int arr [a];
Perhaps this is not the intention of an enum but the members of enums are the closest thing to a constant in C. Unlike the common practice of defining everything using #define, the visibility of a is limited by scope and here it is the same as arr.
A const-qualified variable is not the same thing as a constant expression; a constant expression has its value known at compile time, whereas a const-qualified variable (normally) doesn't (even though it looks like it should).
Note that in C99 and later, it's possible to declare variable-length arrays, where the array size isn't known until run time. You have to use a C99 or later compiler, and given that the feature was made optional in the 2011 standard, you have to check a feature macro to see if VLAs are available:
static const int a = 10; // a is not a constant expression
#if defined( __STDC__ ) && defined ( __STDC_VERSION__ ) && __STDC_VERSION__ >= 199901L && !defined( __STDC_NO_VLA__ )
/**
* VLAs are available in this environment
*/
#define USE_VLA 1
#endif
#ifdef USE_VLA
int arr[a];
#else
/**
* VLAs are not available, either because it's a pre-1999 implementation,
* or it's a post-2011 implementation that does not support optional
* VLAs. We'll have to use dynamic memory allocation here, meaning we'll
* also need an explicit free call when we're done with arr
*/
int *arr = malloc( sizeof *arr * a );
#endif
...
do_something_interesting_with( a );
...
#ifndef USE_VLA
free( a );
#endif
At least up until very recently, Microsoft's C compiler did not support VLAs. They have been adding some C99 features, though, such as mixed declarations and code, so maybe the latest version supports VLAs. I don't know.

for loop initial declaration error

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.

Declare C89 local variables in the beginning of the scope?

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.

Resources