0

I am trying to code a simple macro which based on a condition either calls break or continue in the loop in which it is called. Below is the code:

#include <iostream>

#define BC_IF_EVEN(BC) if(i % 2 == 0) BC

using namespace std;

int main() {
    int i = 0;
    while(i++ < 30) {
            if(i < 15)
                    BC_IF_EVEN(continue);
            else
                    BC_IF_EVEN(break);

            cout << i << " ";
    }
    cout << endl;
}

The output that I am looking for is: 1 3 5 7 9 11 13 15, but the above code outputs: 1 3 5 7 9 11 13 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 because the else condition in main() gets applied to the if condition in the BC_IF_EVEN macro.

A simple fix is to put scope braces for the if condition in main(), but I do not want to enforce that because the user should be allowed to code in regular way.

N.B. I cannot put a do { .. } while(false) loop in the macro (which is a standard trick to allow semicolons after macro calls in conditionals because the break and continue sent via BC get applied to this inner loop.

Is there an easy way to get the required output without modifying the main() function?

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
John Elaine
  • 359
  • 5
  • 22
  • 1
    What are you trying to accomplish? I don't understand the point of this exercise at all. – Dai Sep 04 '15 at 05:10
  • There is a flag in my code which I need to check at various places based on which I need to break or continue. Instead of putting those two lines and making my code look confusing (full of conditionals), I was planning to add a macro call for each check. – John Elaine Sep 04 '15 at 05:13
  • 3
    Don't code like this, it is unreadable code. Control flow is very important to understand, so keep it explicit. – Basile Starynkevitch Sep 04 '15 at 05:14
  • 2
    Macros would only make it more confusing, trust me. Avoid using the preprocessor wherever possible. – Dai Sep 04 '15 at 05:15
  • Just put the conditional expression into a helper function `if (even(i)) break;` – Ryan Haining Sep 04 '15 at 05:20
  • @BasileStarynkevitch, Dai: I was in two minds due the same concern that you'll have raised, but I was ready to go ahead with the macro solution because the call has clear "break" and "continue" in them -- which is better than just being a simple call. But, yes it is still fairly unreadable. – John Elaine Sep 04 '15 at 05:21
  • @JohnElaine Do not try to re-invent the C language. Instead of making the code readable, you turned it into a confusing mess. You achieved the opposite of what you were trying to avoid. In addition, if your code is full with continue and break, that means that your program is full of obscure loops that should be rewritten. – Lundin Sep 04 '15 at 06:43

6 Answers6

5
#define BC_IF_EVEN(BC) if (i % 2 != 0); else BC

but really WHY?

john
  • 85,011
  • 4
  • 57
  • 81
2

Don't invent obscure macros in an attempt to justify your obscure loops. Frequent use of continue and break inside loops is a certain sign of poor program design.

Here's how to fix the program:

  • When the amount of items you iterate through is known in advance, use a for loop, as they are usually easier to read and harder to mess up.
  • Since you check if a number is even no matter in which way the program branches, might as well move that check outside the if-else.

    for(int i=0; i<30; i++)
    {
      if(i%2 == 0) // even
      {
        if(i < 15)
          continue;
        else
          break;
      }
    
      cout << i << " ";
    }
    
  • Now look at the conditions and what the program actually does. This doesn't make sense at all. All it does is to print the odd numbers between 0 and 14 in a very obscure way. Instead, you probably wanted a program which prints the odd numbers between 0 and 15.

  • Apply common sense: Loop from 0 to 15. Check each number to see if it is odd. If so, print it. Otherwise ignore it.

    for(int i=0; i<=15; i++)
    {
      if(i%2 != 0)
        cout << i << " ";
    }
    
  • Alternatively, don't bother with even numbers at all:

    for(int i=1; i<=15; i+=2)
    {
      cout << i << " ";
    }
    
Lundin
  • 195,001
  • 40
  • 254
  • 396
0

This is why functions were created, just create a function to check if it is even or odd and return a true if even and false if odd. Macros are ugly when you can do it simply another way. Please for the love all legacy maintainers make readable code.

eg:

// Example program
#include <iostream>


using namespace std;

bool checkeven(int i)
{
    if( i % 2 != 0)
    return false;

    else
    return true;
}

int main()
{
    for(int i = 0; i < 30; i++)  //while(i++ < 30) is readable, but I think this is even easier
    {
        if(i < 15)
        {
            if(checkeven(i))
                continue;
        }

        else
        {
            if(checkeven(i))
                break;
        }
            cout << i << " ";
    }
}
Futuza
  • 144
  • 8
0

Use curly brackets even if you have the only line in if/else statement. In this case you'll fully control the workflow.
The other advantage of this approach is that if you need to comment out the line in if/else statement you'll just put // in the start of the line.

// wrong workflow
if ( expr )
    // commented out for debug issues
    //do_when_expr();
do_whatever();

// right workflow
if ( expr )
{
    // commented out for debug issues
    //do_when_expr();
}
do_whatever();

In your case it would be:

#define BC_IF_EVEN( BC ) if (i % 2 == 0) { BC; }

...
    if(i < 15)
    {
        BC_IF_EVEN(continue)
    }
    else
    {
        BC_IF_EVEN(break);
    }
borisbn
  • 4,988
  • 25
  • 42
0

Try this

#define BC_IF_EVEN(BC)  ( { if(i % 2 == 0) BC; } )
Nishant
  • 2,571
  • 1
  • 17
  • 29
0

You just need an extra pair of curly braces to restrict the scope for your inner if block. Following should work:

#define BC_IF_EVEN(BC) {if(i % 2 == 0) BC;}

Also do not use ';' while using macro:

            if(i < 15)
                BC_IF_EVEN(continue) //No semicolon

Or if you want use semicolon for code consistency then an extra pair of braces has to be put:

#define BC_IF_EVEN(BC) ({if(i % 2 == 0) BC;})