In many programming competitions I have seen people write this type of for
-loop
for(i = 0; i < (1 << 7); i++)
Unless I am missing something, that's the same as
for(i = 0; i < 128; i++)
Why use the (1 << 7)
version?
Isn't calculating the condition every time an unnecessary overhead?
A constant expression gets evaluated at compile time, not run time, and can be used in any place that a constant can be used. The constant expression must evaluate to a constant that is in the range of representable values for that type.
If the condition is true, the "body" of the loop is executed. If not, control passes to the statement (if any) directly after the body of the loop. After the body is executed, the "change" is done. This can be increment, decrement of the initialized variable(s) or something else.
Condition is an expression that is tested each time the loop repeats. As long as condition is true, the loop keeps running. Increment is an expression that determines how the loop control variable is incremented each time the loop repeats successfully (that is, each time condition is evaluated to be true).
A "While" Loop is used to repeat a specific block of code an unknown number of times, until a condition is met. For example, if we want to ask a user for a number between 1 and 10, we don't know how many times the user may enter a larger number, so we keep asking "while the number is not between 1 and 10".
Yes, they are equivalent in behavior.
Then why do people use the (1 << 7) version?
I guess, they use it to document it is a power of 2.
Calculating the condition every time must be an overhead! I am unable to find the reason behind this!
Not really, any normal compiler will replace 1 << 7
by 128
and so both loops will have the same performances.
(C11, 6.6p2) "A constant expression can be evaluated during translation rather than runtime, and accordingly may be used in any place that a constant may be."
Let's translate each one of these options into plain English:
for(i = 0; i < (1 << 7); i++) // For every possible combination of 7 bits
for(i = 0; i < 128; i++) // For every number between 0 and 127
Runtime behavior should be identical in both cases.
In fact, assuming a decent compiler, even the assembly code should be identical.
So the first option is essentially used just in order to "make a statement".
You could just as well use the second option and add a comment above.
1 << 7
is a constant expression, the compiler treats it like 128
, there's no overhead in run time.
Without the loop body, it's hard to say why the author uses it. Possibly it's a loop that iterates something associated with 7 bits, but that's just my guess.
Then why do people use the (1 << 7) version?
It is a form of documentation, it is not a magic number but 2^7
(two to the seventh power) which is meaningful to whomever wrote the code. A modern optimizing compiler should generate the exact same code for both examples and so there is no cost to using this form and there is a benefit of adding context.
Using godbolt we can verify this is indeed the case, at least for several versions of gcc
, clang
and icc
. Using a simple example with side effects to ensure that the code is not totally optimized away:
#include <stdio.h>
void forLoopShift()
{
for(int i = 0; i < (1 << 7); i++)
{
printf("%d ", i ) ;
}
}
void forLoopNoShift()
{
for(int i = 0; i < 128; i++)
{
printf("%d ", i ) ;
}
}
For the relevant part of the code we can see they both generate the following see it live:
cmpl $128, %ebx
What we have is an integer constant expression as defined in the draft C11 standard section 6.6
Constant expressions which says:
An integer constant expression117) shall have integer type and shall only have operands that are integer constants, enumeration constants, character constants, sizeof expressions whose results are integer constants,[...]
and:
Constant expressions shall not contain assignment, increment, decrement, function-call, or comma operators, except when they are contained within a subexpression that is not evaluated.115)
and we can see that a constant expression is allowed to be evaluated during translation:
A constant expression can be evaluated during translation rather than runtime, and accordingly may be used in any place that a constant may be.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With