I'm discussing with a friend what's the correct way to declare some variables in C, exactly in the for loop.
He has a compiler I can't remember and I have Dev-C++.
He does:
for (int i = 0; i<10; i++)
// ... and it works
I do:
int i;
for (i = 0; i<10; i++)
// ... and it works
If I do it like he does, Dev-C++ gives me an error. What's the technically correct way to do this? I was taught to do it the way I do but now I'm confused because he does it in the other way and it works for him D:
Declaring the variable in the loop, like your friend does, is supported in C99 and in C++. It is likely that your friend is coming from a C++ background, where such style of declaration is the norm. Declaring the loop variable outside the loop, like you do, is correct in older C, such as C89, which is what your compiler apparently supports.
If you have access to a C99 compiler, which style to choose is mostly a matter of preference. Seasoned C programmers don't mind declaring variables outside loop bodies, but it is considered slightly cleaner to declare them inside because it restricts the scope of the variable to the least possible lexical region. Declaring the variable outside the loop body is, of course, necessary if you plan to use it after the loop is done — for example, to inspect how far the loop has progressed.
Depending of which version of C you're using. Ansi C (original, Ritchie & Kernighan) only supports declaration at begin of block while modern C (and any flavour of C++) allows mixing statement and declaration.
{
int a;
printf ("Stuff);
int b; /* not allowed */
}
Declaring a value inside of the for-loop header causes an error in any compiler that predates c99. If you compile this with the c99 standard or newer, it will work just fine.
Formally the physical difference between THESE TWO is the performance. put the definition within the brackets after for may have more chances to be as a register-only variables. But on the other hand there are many other factors which can decide the detail of optimization results, with the help of the analizing mechanism of the compiler. So the final result may be no different or even be opposite.
There is indeed a different for sure: if you define a variable within the brackets after 'for', that variable won't be able to be used at the outside of that for-loop.
Related
The following example is illegal C program, which is confusing and shows that a declaration is not a statement in C language.
int main() {
if (1) int x;
}
I've read the specification of C (N2176) and I know C language distinguish declaration and statement in the syntax specification. I told my teacher who teaches compiler, and he seems not believe it and I cannot convince him unless I showed him the specification.
So, I am also really confused. Why C is designed like this? Why a declaration is not a statement in C? How to convince someone of the reason of this design?
Because there is no apparent grammatical or technical semantic reason that a declaration cannot appear wherever a statement may appear, this appears to be largely due to history and lack of utility.
Considering the Grammar
Statements enter the C grammar in the function-definition rule, in which a compound-statement appears. A compound-statement allows a statement. Then inspecting the replacements for a statement reveals the places where a statement may appear but a declaration may not:
In a labeled-statement, after a label followed by :.
In a selection-statement, after the ) of an if or a switch or after an else.
In an iteration-statement, after the ) of a while or for or after a do.
The following is not a formal analysis of the grammar, but it appears the places where a statement may appear but a declaration may not are quite limited: After the : that ends a label, after a keyword (else or do) or after the closing ) for a ( that immediately follows a keyword (if, switch, while, or for). These seem to me like unambiguous points in the grammar, where it should be as easy to distinguish declarations and statements as it is to do so after a ; in a compound-statement.
Therefore, I do not think there is a grammatical reason not to allow a declaration to appear anywhere a statement may appear (or, equivalently, to define a declaration as a kind of statement).
Considering the Semantics
Now consider the semantic effects of allowing declarations in the places where currently a statement may appear but a declaration may not.
In the case of a labeled-statement, where we desired to have label: declaration, we can use label: ; declaration, where we have inserted a null statement after the :. The result is a defined code sequence with semantic effect equivalent to what we would desire to have by allowing a declaration immediately after the label.
In the other cases, where we desire to have declaration, we can use { declaration }. Again, the result is a defined code sequence with semantic effect equivalent to what we would desire to have by allowing a bare declaration. That effect is minimal; any expressions in the declaration (in array declarators or initializers) will be evaluated, but anything that is declared goes out of scope immediately. Note that even if the scope were not ended by the closing }, it is ended by the fact that the C standard defines each of these places to be a block. (C 2018 6.8.4 3 says the substatement of a selection-statement is a block, and 6.8.5 5 says the loop body of an iteration-statement is a block.)
Nonetheless, this shows there is no technical semantic impediment to allowing a declaration wherever a statement may appear.
Conclusion
Since the grammar and semantics of C apparently do not preclude allowing a declaration to be a type of statement, we are left with reasons of history and utility. In C as described in the first edition of Kernighan and Ritchie’s The C Programming Language, the locations of declarations were limited. Inside functions, they could only appear at the start of a compound statement. A declaration could not follow a statement. As we see from modern C, there was no grammatical or semantic reason for this limitation; we can allow declarations anywhere within a compound statement. So it seems simply that, around 1978, work on the language had not progressed that far.
Similarly, it seems that current work on C has not gone to the point of allowing a declaration to appear anywhere a statement may appear, as if it were a type of statement, even though there may be no technical impediment. However, in this case, there is less motivation for loosening the rules. Of the above cases, the only one that is of much use is allowing a declaration in a labeled statement. And, as its desired effect is easily accomplished by inserting a null statement, there is likely insufficient motivation to change compilers and to advocate for the changes in the C committee.
That's because a declaration doesn't instruct the compiler to do anything, it's purely informative for the compiler; at least by the standard. Compilers may do something if they see a declaration, the standard does not forbid it either but it doesn't require them to do anything if they only see a declaration and whatever it declares is never used within any statement.
Consider this code:
int main ( )
{
int x;
printf("Hello World!\n");
return 0;
}
What do you think will int x; do? You are declaring that x is of type int but you are never using x anywhere in the rest of the code. The compiler doesn't even have to reserve any memory on stack for it. It may to so but it isn't required to do so.
The standard allows the compiler to create exactly the same code as if you had written:
int main ( )
{
printf("Hello World!\n");
return 0;
}
There is simply nothing a compiler must do if you let it know the type of a variable. This variable doesn't have to exist anywhere at all unless it is ever used by a statement.
C is not an interpreted language where every piece of code instructs the interpreter to directly do something. C is a compiled language which means you tell the compiler to generate CPU code for you that performs the actions you described in a predefined language. So there is no one-to-one relationship between the code you write and the CPU code the compiler generates.
You may write
int x = a / 8;
but the CPU code that the compiler generate may be equivalent to
int x = a >> 3;
As that is exactly the same thing and if shifting is faster than division (and you can bet it is), the compiler does not have to generate a division just because you told it to do so. What you told the compiler is "I want x to be one eighth of a" and the compiler will be like "okay, I'll generate code that makes this happen" but how the compiler is making it happen is up to the compiler.
Thus the compiler only needs to translate statements to CPU code. Actually only statements that have an effect but to find out about that expensive analysis may be required so it's no standard violation to translate all statements to code, even those that do nothing. A declaration on its own has never an effect, it just lets the compiler know the type of a variable or function, which may become important in statements later on but only if the variable/function is ever actually used.
If it were valid, what would you like this program to do ? :
#include <stdio.h>
int main (int argc, char **argv)
{
if (argc > 1) int x=42;
printf("%d\n", x);
return 0;
}
Is there a difference between the following two approaches to defining a for-loop variable in C?
int i;
for (i = 0; i < X; i++) {
// something
}
And:
for (int i = 0; i < X; i++) {
// something
}
My preference is to use the second approach if the i is just always a throw-away, but is there any reason that it wouldn't be a good idea to do that?
Yes.
As the i variable is usually used only to count the number of iterations needed, it doesn't make sense to have a variable live outside the scope of the loop. That, if you can, should be avoided.
As some comments to the question mention, there are some cases in which you can't use the second, but that's not the general case.
As for the compiler later compiling to the same assembly, that may be true, but conceptually the second is cleaner, and for someone reading the code from outside, it makes it clear that the variable is never used again.
Hope this helps!
but is there any reason that it wouldn't be a good idea to do that?
In C, you should prefer the second form, because it reduces the scope of the variable and makes it more obvious where it is going to be used. Unless...
...it goes against the coding guidelines of a given project. For instance, the Linux kernel declares all variables at the top of a function.
...you want to be conforming to C90: you cannot use loop initial declarations.
In C++, however, objects may have very expensive constructors, which means that, at times, you may want to re-use them rather than initialize a new one every time (e.g. if you construct a new one within the body of the loop).
There are a number of differences between the two.
The second form is illegal in the 1989 ANSI (1990 ISO) C standard. The first is supported in C from 1999 and in standard C++. It is supported by some C compilers older than 1999, either as a non-standard or optional extension or because those compilers were actually C++ compilers with a C mode.
In the first form, i exists after the loop, so its value can still be accessed, but redefining it results in a diagnostic (compile time error). In the second form, i does not exist after the loop, so accessing its value after the loop gives a diagnostic, but i can be redefined.
In general terms, it is advisable to ensure that variables only exist for as long as needed, and cease to exist when no longer needed. The second form explicitly allows that.
Obviously, variables that need to exist outside the loop, need to be defined outside it. But, if the variable i is not needed outside the loop, then I would favour the second form. This allows the compilers to catch problems, such as unintended use of variable i after the loop.
Some older C and C++ compilers (mainly dating from before the 1998 C++ standard was ratified, but some from the early 2000s) implement the second form so the variable i still exists after the loop. This effectively makes the two forms equivalent when using those compilers.
Is there a way to check if a variable has been initialized or not in C?
Consider the following example,
int main(){
int a = 3, b = 7, c;
if ( a > b )
c = a-b;
// Now, how can I check if the variable "c" has some value or not
// I don't want check like this,
// if ( isalpha(c) ) or if ( isdigit(c) )
// or anything similar to like that
}
In other words, does C has some function like defined in Perl. In Perl, I can simply do if (defined c)that would check if the variable is defined or not, and it'd return False for above example. How can I achieve the same in C?
C does not have this ability. You have two main options:
A sentinel value
For example, if you know that the value of c will never be negative, then initialize it to -1, and test that for that.
Add another variable
Create another variable bool we_set_c_to_something = false; and then set it to true when you write to c.
C is a compiled language which doesn't support runtime variable binding, while Perl is a interpreted language which support dynamic typing. So you can check the definition of a variable in Perl, but not in C.
When you declare a variable in C int c;, this variable c is defined but without initialization. The declaration and definition are in one statement.
The definition of a variable in C is not checked by code writer. The compilers do it for you. When compile and link your C code, the compiler will check all variable's definitions. An error will be invoked and the compiling or linking process will stop if there are undefined variables found in your code.
Hope this will make you distinguish the differences.
Wrong question. You're not asking whether the variable is defined. If the variable is not defined then compilation fails. Look up the difference between "declaration" and "definition". In the case of those local variables, you have defined the variable c.
What you're looking for is initialisation. Many compilers will warn you about using variables before they're initialised, but if you persist in running that code then the assumption is that you know better than the compiler. And at that point it's your problem. :) Some languages (e.g. Perl) have an extra flag that travels along with a variable to say whether it's been initialised or not, and they hide from you that there's this extra flag hanging around which you may or may not need. If you want this in C, you need to code it yourself.
Since C++ allows operator overloading, it's relatively easily to implement this in C++. Boost provides an "optional" template which does it, or you could roll your own if you want a coding exercise. C doesn't have the concept of operator overloading though (hell, the concept didn't really exist, and the compilers of the day probably couldn't have supported it anyway) so you get what you get.
Perl is a special case because it rolls the two together, but C doesn't. It's entirely possible in C to have variables which are defined but not initialised. Indeed there are a lot of cases where we want that to be the case, particularly when you start doing low-level access to memory for drivers and stuff like that.
This question already has answers here:
Declaring variables inside loops, good practice or bad practice?
(9 answers)
Closed 7 years ago.
let's assume that it is not only in visual studio but also in C99, C11 and etc.
there are two different ways of declaring variable "i" in for statement.
1)
int i;
for(i = 0 ; i < index ; ++i)
2)
for(int i = 0 ; i < index ; ++i)
Both work same. but I think there will be some difference between them.
Do you have any idea about that?
If yes, please let me know.
I just wondering about your opinion, and how it works differently.
Sorry. for answers, I know that the scope of "i" is different.
Is there any difference in view of system(I mean memory or etc.) or compiler work differently or assembled code is different or something like this.
The only difference is that in the first case, the variable i is outside for scope so you could use it later on. There are no differences in term of efficiency.
If you use i only once, then definitely the 2nd case is better:
for(int i = 0 ; i < index ; ++i)
If you have loops that use index i, then it might make sense declaring it outside all loops.
But generally, the rule is to limit the scope of the variable - so the 2nd case is better. It's usually safer to limit the scope of the variable.
It'd worth noting that the 2nd case syntax only works with C99 or newer C11 (did not work with old C89). So some compilers would complain if you declare variable inside the loop. For example, gcc requires explicit flag -std=c99 to allow that syntax.
The scope and lifetime of i is different.
In the second example it is just inside the loop body. In the first, it extends beyond.
Apart from that, they are equal.
Declaring a new variable in the initialization of the for loop is a C99 extension.
C89 requires that variables be declared at the beginning of a block.
Semantically, declaring variables in the initialization portion of the loop would limit the variables' scope to the body of the loop.
Limiting the scope is often desired to avoid misuse of variables after the body of the for loop has executed. For example, if you are doing a simple iteration, you may not want your index to exist after the for loop.
There is no right answer on which to use. The question becomes what you want your scope to be, and what compilers/language versions you intended to support.
In C99 the correct way is No 1). It requires the variables are declared before use. Looks like your compiler supports several standards, therefore it looks transparent to you what construction to use, and they all result in the same behavior. My personal preference in this case is 2) because it reduces scope of the variable i, and also prevents from unitialized value use (less risky).
I am using XC32 compiler by Microchip, and it does not allow declaration of variables inside loops (does not support C99), so I can not do this:
for(int i = 0;i<10;i++)
{do w/e}
I would hate to make it a global, because it would be hard to keep track of it's value in big projects, using the same thing in various loops, even if you initialize it to i = 0 in every loop. I even had a bug with this, when it turned out to do weird stuff if you have a few nested loops using the same i.
As far as I understand, I can't "undeclare" it manually, but variables defined inside a block of code are undeclared after the pass trough the block? Is this true, and does that mean that this this code will act like the code above:
{
int i;
for(i = 0;i<10;i++)
{do w/e}
}//no i anymore?
According to C99 standard, the scope of a variable declared in the clause statement of the for loop is restricted in scope to that loop.
In C89 / C90, that clause is merely an optional expression.
Therefore in C89 / C90 you can confidently emulate the C99 behaviour with
{ /*open scope block*/
/* your declaration here, including possible definition*/
for (expression; ...){
}
} /*close scope block*/
By putting it in a block you will indeed be rid of it at the conclusion of the block in question.
What this means exactly, however, depends on the compiler, the architecture, and the environment.
The variable scope is inside the block in which it is defined. So once the block is finished you cannot access the variable.
You may find this helpful:- Local variables display as “Out of Scope” when they are most clearly NOT out of scope.