-1

Instead of having two different loops that have identical printf statements, you can make a for loop that uses a boolean and ternaries to switch it forward or backward.

Why is this bad form? Because it's unreadable? Does the compiler make two different loops, anyways?

Just curious as to what this means for the compiled result.

Example:

for (int i = (forward == true ? 0 : 10);
    (forward == true ? i <= 10 : i >= 0);
    (forward == true ? ++i : --i))
    printf(" %d", i);

Instead of:

// Forward
for (int i = 0; i <= 10; ++i)
    printf(" %d", i);

// Backward
for (int i = 10; i >= 0; --i)
    printf(" %d", i);

I was given this interesting suggestion:

  for (int i = 0; i < 10; i++) {
        printf(" %d", (forward ? i : 9-i));
  }

After checking the assembly code using Godbolt, it is possible that the compiler will make one (complicated) or two (simplified) loops.

5
  • Note forward == true is poor code. Better as forward. Commented Jan 20, 2023 at 0:53
  • 1
    If you want to know what it means for the generated code, put it into godbolt and see what the code looks like. This might be too complex for the compiler to optimize, but I'm constantly surprised at how clever modern compilers are. Commented Jan 20, 2023 at 0:53
  • At the very least you should fix the indentation so it's clearer which parts of the code are inside the for-loop header rather than the body. Commented Jan 20, 2023 at 0:54
  • 1
    Are these two code blocks even equivalent? I don't see where the first version is toggling forward so it switches to backwards when it reaches 10. Or is the second snippet supposed to be two alternative loops, not one after the other? Commented Jan 20, 2023 at 0:56
  • @Daniel Notice the 2 code snippets are not the same and the 2nd lacks a test based on forward. Commented Jan 20, 2023 at 0:57

4 Answers 4

3

why is this bad form? Because it's unreadable?

Yes it is bad because it is unreadable.

C does not required a single or two different loops. The emitted code is an implementation defined issue.

In general, with such micro optimizations consider:

Save your valuable time to deal with bigger issues.

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you. That is what I suspected, although I wondered if there was a slight performance gain that might make a difference in certain contexts (Arduino, etc.).
@Daniel "if there was a slight performance gain" --> Maybe. Consider the time spent on seeking a slight performance gain is better spent on other issues were there is a big performance gain or more time to with family/friends. IOWs, even if true, is it worth it? Would you encourage your staff of programmers to seek some minor improvements or have them working on other tasks?
3

C is just about perfectly general in the way it allows and evaluates expressions, so you can put virtually whatever jawbreaker expression you want into any (or all three) of the controlling expressions of a for loop (or anywhere else C expects an expression), and it should work.

I have used ?: in for loop headers, although as other answers have suggested, it can pretty rapidly get unreadable.

If I had to write a general, up-or-down loop such as you asked about, I'd probably do it like this:

int start, end, dir;

if(forward) {
    start = 0;
    end = 10;
    dir = +1;
} else {
    start = 10;
    end = 0;
    dir = -1;
}

for(int i = start; i != end; i += dir) {
    …
}

For any of the loops we've discussed here (those you initially asked about, or in any of the answers), the performance is probably going to be virtually identical. Details like this have never mattered much, and with ever-faster CPUs and ever-more-aggressively-optimizing compilers, they make even less difference today. As always, if you really care, you'll have to perform careful measurements, and/or inspect the generated assembly code. Human predictions about performance at this level are rarely accurate or useful.

1 Comment

Another tiny comment... The OP code will print the last value as "10" (or "0") whereas....
2

Your existing code can be significantly simplified:

#include <stdio.h>
#include <stdbool.h>

int main(void) {
    bool forward = false;
    for (int i = 10*!forward; i <= 10 && i >= 0; i += 2*forward - 1)
    {
        printf(" %d\n", i);
    }
    return 0;
}

  • int i = 10*!forward : Set i to 0 or 10, depending on forward
  • i <= 10 && i >= 0 : Keep going, as long as i is between 0 and 10
  • i += 2*forward - 1 : Update i by +1 or -1, depending on forward

When forward is set to false, the loop outputs:

 10
 9
 8
 7
 6
 5
 4
 3
 2
 1
 0

And when forward is set to true, the same loop outputs:

 0
 1
 2
 3
 4
 5
 6
 7
 8
 9
 10

I believe that is what you wanted?

Where the behavior of the same loop could go either way, depending on forward := [true | false]

3 Comments

i <= 10 && i >= 0; --> Sneaky and nice!
BTW: As a Trekkie, I like code that has "10-Forward". :)
That is cool, but still suffers from unreadability. I was more or less wondering how the compiler would handle it, specifically in terms of what would end up being more performative.
0

Compilers deal with complexity far better than humans. Yes, the first example is difficult to read.

Very much in the spirit of the answer given by @SteveSummit, the boundaries and "direction" can be clearly specified outside the loop.

The following alternative "knows" that there will be at least one value printed.

#include <stdio.h>
#include <stdbool.h>

int main( void ) {
    bool forward = false;
    int st = 0, inc = 1, end = 10;
    if( !forward ) st = 10, inc = -1, end = 0;
    do printf( " %d", st ); while( (st += inc) != (end + inc) );
    return 0;
}
 10 9 8 7 6 5 4 3 2 1 0

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.