This question already has answers here:
Why do for(;;) loops behave like infinite loops?
(2 answers)
Closed 5 years ago.
I've written infinite loops like this numerous times over the years in both C and C++, but today is the first time I really thought about it -- why is it an infinite loop when the condition clause is empty? One would expect you'd have to write something like for(;true;); to get a valid infinite loop?
while(); doesn't compile nor does while(;);
Anyways, I like the for(;;); syntax and use it often, but is it a special case to treat an empty condition block as true or are there other cases in C or C++ where an empty condition expression is interpreted as true?
The C Standard explicitly describes this behavior of for loops:
C11 Draft Standard §6.8.5.3 2
Both clause-1 and expression-3 can be omitted. An omitted expression-2
is replaced by a nonzero constant.
Similarly, for C++:
C++14 Draft Standard §6.5.3
2
Either or both of the condition and the expression can be omitted.
A missing condition makes the implied while clause equivalent to
while(true).
The behaviors are defined by the language (C++). For the for loop, the condition part is optional:
Syntax
formal syntax:
attr(optional) for ( init-statement condition(optional) ; iteration_expression(optional) ) statement
and (emphasis mine)
The above syntax produces code equivalent to:
{
init_statement
while ( condition ) {
statement
iteration_expression ;
}
}
Except that
3) Empty condition is equivalent to while(true)
For while loop, the condition part is necessary, it can't be ommitted.
Syntax
attr(optional) while ( condition ) statement
Related
I am looping through indices and I am checking if I am not in the first loop interation and another condition. I don't want the second condition to be evaluated if the first is .False..
do i = 1, n
if ( i /= 1 .and. var(i) > var(i-1) ) then
do something
end if
end do
Clearly in this scenario, evaluating the second condition if the first condition is false will lead to an index error. Since if i = 0 then var(i-1) will be below the lower bounds.
Why is the second condition evaluated if the first is already .False.? Is there a way to avoid this without create a second if statement?
The shortest answer is 'no'. For the code shown, you have two option
do i = 1, n
if ( i /= 1 ) then
if (var(i) > var(i-1) ) then
do something
end if
end if
end do
or
do i = 2, n
if (var(i) > var(i-1) ) then
do something
end if
end do
Fortran currently does not allow safe use of the form of the question: a compiler is free to evaluate all operands of an expression if it chooses and such operands in the program must conform to the requirements of the standard. A compiler is allowed not to evaluate the var(i) > var(i-1) operand when the i /= 1 operand evaluates as false (Fortran 2018, 10.1.7):
It is not necessary for a processor to evaluate all of the operands of an expression, or to evaluate entirely each operand, if the value of the expression can be determined otherwise.
This does not, however, give the programmer licence to assume the compiler will skip an evaluation, or will evaluate in a particular order.
We can see this clearly in the deliberations of the Fortran standards committee. There has been over time proposals to introduce such things as the .andthen. and .orelse. operators motivated by the similar case:
The poster-child use-case is something like
if( I <= NMAX .and. A(I) > 0.0 )then
where the intention is to evaluate A(I) only when I is in-bounds.
So far such proposals have not made it in to the language (F2018 standard or F2023 draft), but most recently this has been noted as worthy of ongoing consideration.
steve's answer shows how the case of the question can be safely written in the absence of these or similar operators.
Note: the striked text below results from a wild interpretation of the standard, which is probably wrong, so I have edited these parts. As a matter of fact, in the example with the foo() function the Intel compiler never skips the evaluation of foo(c)==0, but gfortran does skip it whenever possible and when compiling with -O3)
In Fortran something like expr1 .and. expr2 is considered as a single expression that has to be fully evaluated. As in any expression the compiler is free to evaluate the sub-expressions in any order. It is also free to not evaluate one of the sub-expressions , as long as it has no side-effect compared to a complete evaluation (edited: if it not necessary).
It means that in (i /= 1) .and. (var(i) > var(i-1)), the compiler is free (but not required to) skip the evaluation of (var(i) > var(i-1)) if it has already evaluated (i /= 1) to false (i.e. `i is equal to 1).
However if you have (i /= 1) .and. (foo(c) == 0)) with foo() being a function that can modify c, e.g.
integer function foo(counter)
integer, intent(inout) :: counter
foo = mod(counter,10)
counter = counter + 1
end function
Then the compiler is required to evaluate foo(c) == 0, whichever the evaluation of (i /= 1) (note that it could possibly skip the evaluation of (i /= 1), though). (edited: this is actually the same as above, the compiler may (but again is not required to) skip the evaluation of foo(c) == 0, meaning the the value of c may get undefined).
In C expr1 && expr2 is not really an expression, one could rather see it as a construct with specific rules for the evaluation of the expressions.
I came through this code snippet while I was referring to C++ multiple-choice questions. Previously I used only && or || for combining multiple conditions, but this code uses ',':
using namespace std;
int main()
{
int i;
for (i = 0; i < 0, 5; i++)
printf("%d ", i);
return 0;
}
Formally, the answer for this one is an infinite loop. What is the working of this snippet? How are the conditions getting evaluated?
You have a comma operator in the condition of your for loop. The comma operator evaluates its first operand and discards the result, and then evaluates the second operand and returns this value (and type). The comma operator also has the lowest precedence of all C/C++ operators, meaning it's always the last one to bind to an expression.
So the condition in your for loop is equivalent to:
(i < 0), 5
The result of this expression is always 5, which is not 0 (false). Hence the condition is always true.
If you leave loop running for long enough eventually i, which is a signed integer, will overflow. This results in undefined behaviour (thanks #Jarod42).
In function 'int main()':
10:16: warning: left operand of comma operator has no effect [-Wunused-value]
Run your code here and read the warnings.
While I am reading in a code, I found that the loop for was used with just two arguments (the one in the middle is absent). When the program is executed, the loop for is infinite. Here is a minimal working environment. Could anyone tell what is wrong in the code?
// Example program
#include <iostream>
using namespace std;
int main()
{
for (int i = 0; ; i = (i+1)%2)
{
cout << i << endl;
}
}
when you have
for (statement 1;statement 2;statement 3){}
statement 1: performs at entry to the for loop
statement 2: is checked before every new iteration, if it evaluates as 0/false it doesn't continue
statement 3: is performed at end of every iteration regardless.
if you leave statement 2 empty it default to true/1 and so every time it loops it will evaluate as continuing and so will be an infinite loop
There's nothing wrong with the code, it's doing exactly what you told it to do.
The second section of the if statement is the continuation condition which, if omitted, defaults to true.
In fact, you can leave out any combination of the loop initialisation, continuation condition and post-iteration sections and they will default to, respectively:
no initialisation.
continue forever (in the absence of control flow statements like break).
no post-iteration actions.
which is why:
for (;;)
is a perfectly valid infinite loop.
This is explained in the C standard. §6.8.5.3:
1 The statement
for ( clause-1 ; expression-2 ; expression-3 ) statement
behaves as follows: The expression expression-2 is the controlling expression that is evaluated before each execution of the loop body. [..]
2 Both clause-1 and expression-3 can be omitted. An omitted
expression-2 is replaced by a nonzero constant.
That essentially means that it will repeat forever.
A further explanation continues in a footnote (which is considered non-normative):
158) Thus, clause-1 specifies initialization for the loop, possibly
declaring one or more variables for use in the loop; the controlling
expression, expression-2, specifies an evaluation made before each
iteration, such that execution of the loop continues until the
expression compares equal to 0; and expression-3 specifies an
operation (such as incrementing) that is performed after each
iteration.
There is nothing wrong with the code. This allows infinite counting (to an int's limit that is) until an internal condition stops it. None of the three parts of a for loop are necessary, thus any of the below are valid.
for(;;); // Yes, this will never stop
for(int x = 0;;){
}
for(int x = 0; x < 10; ++x);
for(; someCondition != true;){}
And so on, all parts are optional, even the body.
A reason this might be used would be that if one thing is done with the data, I need to stop, but if another thing, I want to do something with it. However, at the same time, I need to know how many times it's happened. You'll use it without all the parameters eventually, but for now, just understand that to have a valid for loop, all you have to have is the top line in my code snippet above.
The syntax for a for loop in C++ is:
for ( init; condition; increment )
{
//statement(s) to be executed while the condition is true
}
See here for more details: http://www.tutorialspoint.com/cplusplus/cpp_for_loop.htm
Your prgram missed the condition statement. Therefore, the for loop repeated forever.
This question already has answers here:
Why is it OK to jump into the scope of an object of scalar type w/o an initializer?
(2 answers)
Closed 8 years ago.
I am confused with variable definition, when playing with goto and switch statements.
The below code were accepted by compiler:
goto label0;
int j; // skipped by "goto"
label0:
j = 3;
My questions are:
Since the definition of int j; is skipped, how will the program create object j and later assign value to it in j = 3 ?
Is the code between goto and label compiled?
Is the code between goto and label executed? (at run-time)
Does variable definition happen at compile-time(or more proper term) or run-time?
(I ask this as a new question focusing more on the relative order of variable definition and compilation and execution. )
Just found another question with close answer:
Why is it OK to jump into the scope of an object of scalar type w/o an initializer?
To summarize and answer the questions:
The goto is a run-time thing. Definition still happens;
Yes it is compiled.
No it is not executed.
Definition happens despite the part skipped by goto.
This is a follow-up to C++, variable declaration in 'if' expression
if( int x = 3 && true && 12 > 11 )
x = 1;
The rules (so far as I can tell) are:
can only have 1 variable declared per expression
variable declaration must occur first in the expression
must use copy initialization syntax not direct initialization syntax
cannot have parenthesis around declaration
1 and 2 make sense according to this answer but I can't see any reason for 3 and 4. Can anyone else?
C++03 standard defines selection statement as:
selection-statement:
if ( condition ) statement
if ( condition ) statement else statement
switch ( condituion ) statement
condition:
expression
type-specifier-seq attribute-specifieropt declarator = initializer-clause
C++11 additionally adds the following rule:
condition:
type-specifier-seq attribute-specifieropt declarator braced-init-list
Generally it means that the declaration you might put inside the condition is in fact nothing more than keeping the value of the condition expression named for further use, i.e. for the following code:
if (int x = 3 && true && 12 > 11) {
// x == 1 here...
x is evaluated as: 3 && true && (12 > 11).
Back to your questions:
3) C++11 allows you now to use direct initialization (with brace initializer) in such case, e.g:
if (int x { 3 && true && 12 > 11 }) {
4) The following: if ((int x = 1) && true) does not make sense according to the definition above as it does not fit the: "either expression or declaration" rule for the condition.