if if if vs if else if else if

Go To Last Post
27 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hey Guys

i would like to know which one is better way of writing code

if(xxxx)
{}
if(xxxx)
{}
if(xxxx)
{}

or

if(xxxx)
{}
else if(xxxx)
{}
else if(xxxx)
{}
else(xxxx)
{}

was just wondering if it would ,akr any difference it the way the code will be used.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Clearly this

if (i < 13)
{
   // Some code here
}
if (i < 42)
{
   // and some code here
}

behaves differently than

if (i < 13)
{
   // Some code here
}
else if (i < 42)
{
   // and some code here
}

Think about these two examples, assuming that i is eg. 7.

Generally speaking, if the alternatives should be mutually exclusive then if - else if - else if... is preferred.

It all depends on what you want the code to do, though.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

So if it is 7, both routines will be followed?

lets say for something like this

if(val == 1)
{
  // and some code here 
}
if(val == 2)
{
  // and some code here 
}
if(val == 3)
{
  // and some code here 
}

then it won;t make a difference right?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

That depends on if the code in the if's affects val.

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

mtlost wrote:
then it won;t make a difference right?

Of course, it can be different.
val can be changed inside the code.

Peter

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

but if it doesn't get changed at all? If val is a constant that never changes?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Then go with a switch-statement instead, much cleaner IMO.

/johan

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I usually go for a switch statement, I was just wondering about this.

Thanx all.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Why worry. Just use whatever seems the most natural and cleanest way to write the code.

The compiler will look after a switch statement AND probably code it better than you.

Hand trace an if, if, if sequence and compare it to an if else, if else, if else sequence. The difference is striking. And yes, a switch statement is an if else block from a logical point of view.

If you have very very time critical code, you can choose the test order of a hand crafted if else block. The compiler is free to write the switch block in its own order. (except for intentionally coded fall-throughs)

I am not sure what avr-gcc does. but many compilers will implement different switch strategies for the number of cases. More than about 20 cases may get changed into ranges. Consecutive cases may get changed to an indexed table. You can fairly safely leave it to the compiler.

On the other hand table driven code with massive tables is best treated that way with indexed tables.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

why is this working

case 0x06 :	Key = 0x00;
			  	if(Pos == 1)				 {
				  Frequency = Frequency - 1000;
				 }
				if(Pos == 2)
				 {
				  Frequency = Frequency - 100;
				 }
				if(Pos == 3)
				 {
				  Frequency = Frequency - 10;
				 }
		   		if(Pos == 4)
				 {
				  Frequency = Frequency - 1;
				 }
				lcd_move_cursor(LCD_LINE_2,10);
    			_delay_ms(30);
				freq_displ();
				_delay_ms(30);
			break;

and this not working?

case 0x06 :	Key = 0x00;
			  	if((Pos == 1) && (Frequency >= 1000))
				 {
				  Frequency = Frequency - 1000;
				 }
				if((Pos == 2) && (Frequency >= 100))
				 {
				  Frequency = Frequency - 100;
				 }
				if((Pos == 3) && (Frequency >= 10))
				 {
				  Frequency = Frequency - 10;
				 }
		   		if((Pos == 4) && (Frequency >= 1))
				 {
				  Frequency = Frequency - 1;
				 }
				lcd_move_cursor(LCD_LINE_2,10);
    			_delay_ms(30);
				freq_displ();
				_delay_ms(30);
			break;

with the last posted code, my LCD does not start up, the micro just doesn't work. I'm going insane about this as I had this roblem the whole day.

When ever I add something to the code, the micro doesn't want to start up the LCD(not even sure if the Atmega8 is starting up).

Everytime I have to make some delays longer and longer and it is slowing down my code so much

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Your two code examples are not logically the same.

If you are initialising an LCD at power-up, you must allow sufficient time for the voltage to rise to 4.5V. Having done that, you follow the timing in the data sheet. A warm-reset does not have this problem.

If you do not check the Busy flag, you must allow 1520us for a CLR command and 760us for a RTN command. All other commands and regular data writes only need the 38us. What do you think you will achieve with waiting 30000us ?

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In the first example, something is always subtracted from Frequency. In the second, you only subtract a value if Frequency is > that number. Not the same. Don't know about any LCD problems.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If i have many if if if statements i usually use a switch statement and depending on the context (eg statemachine) i use an enumeration list for the states. generates more readable code and debugging makes more sense when you see the name of the enumerator pop up un the watch window ;)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

mtlost wrote:
So if it is 7, both routines will be followed?

lets say for something like this

if(val == 1)
{
  // and some code here 
}
if(val == 2)
{
  // and some code here 
}
if(val == 3)
{
  // and some code here 
}

then it won;t make a difference right?

Well it does still make a difference, but not in the way you expect. The final outcome is the same, but the path taken, and the speed through the path is different.

In the code you have shown here, 3 comparisons are done, no matter what the value is. This results in many un-necessary comparisons, which could be a problem for performance critical code.

In the if/else case comparisons are only made until a match is found. So given the same order, a value of 1 yields one comparison, 2 two comparisons, and 3 three comparisons. You can use this to your advantage, by re-ordering the test cases such that the most frequent ones have the shortest comparison path, resulting in faster code.

Writing code is like having sex.... make one little mistake, and you're supporting it for life.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

So if it is 7, both routines will be followed?

You really need to pick up a book on C and read it.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In ICCAVR (V6 at least, haven't checked V7 yet), a switch statement generates 16 bit compares, even if the argument is a byte; quite wasteful if you've got quite a few cases and space and/or timing is tight. if-elseif-elseif can help then. So... a switch is not always the best option :)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes a switch generates 16bit compares, so its perfect for enumerations as they are also 16 bit unless you compile with -fshort-enums :)

I made a quick test program to test the code uasage switch vs if if if vs if else if else if:

int main (void);

unsigned char bar;

void set(unsigned char foo)
{
	bar = foo;
	return;
}


/*
int main () {
unsigned char value;
unsigned char x;

while (1) {
	value = 2;
	switch (value) {
		case 1:
			set(x++);
			break;
		case 2:
			set(x--);
			break;
		case 3:
			set(0);
			break;

	}

}
	return 0;
}
*/

/*

int main () {
unsigned char value;
unsigned char x;

while (1) {
	value = 2;
	if (value == 1)
			set(x++);
	if (value == 2)
			set(x--);
	if (value == 2)
			set(0);

	}


	return 0;
}

*/


int main () {
unsigned char value;
unsigned char x;

while (1) {
	value = 2;
	if (value == 1)
			set(x++);
	else if (value == 2)
			set(x--);
	else if (value == 2)
			set(0);

	}


	return 0;
}

I compiled with gcc -O0 ( with -Os the program does not run casue it gets fully optimized away :P )

switch: 318 bytes
If if if: 290 bytes
if else if else if: 294 bytes

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I slightly modified the test program by making value volitile so that the comparisons would not be optimized out.

switch: 330(-O0), 194(-Os)
if if if: 306(-O0), 202(-Os)
if else if else: 310(-O0), 210(-Os)

So it seems that avr-gcc is doing a better job ( if only slightly ) of optimizing the switch in this case.

Martin Jay McKee

Using an out of date, WinAVR 20070525 ( this machine doesn't get much development use... )

As with most things in engineering, the answer is an unabashed, "It depends."

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

But since you made value volatile, the compiler couldn't do all the optimization that it could. Try making where the value of value comes from volatile and then see the result (such as "value = PINB").

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

so when you need time critical aps, if else is the better way to go. If you don't need time critical aps then you can use what ever way.

Thanx guys. Didn't know this topic would get so much response.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This thread title reminds me of the following.

A sign writer was painting a new sign for a pub called the Bell and Gate. Some nosey parker comes up to him to tell him that

"the space between Bell and and and and and Gate is different"

:lol:

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

:)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

mckeemj wrote:

Using an out of date, WinAVR 20070525 ( this machine doesn't get much development use... )

Perfect, I was using the same release!

whats next, comparing code execution time ?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I made a slightly different version, initializing value and x from volatile values, and making set update a volatile value.

#include 

int main (void);

void set(unsigned char foo) {
  PORTB = foo;
  return;
}

int main () { 
  unsigned char value=PINB;
  unsigned char x=PIND;

  while (1) {
#if SWITCH
    switch (value) {
      case 1:
        set(x++);
        break;
      case 2:
        set(x--);
        break;
      case 3:
        set(0);
        break;
    }
#elif IFIFIF
    if (value == 1)
      set(x++);
    if (value == 2)
      set(x--);
    if (value == 2)
      set(0);
#elif IFELSE
    if (value == 1)
      set(x++);
    else if (value == 2)
      set(x--);
    else if (value == 2)
      set(0);
#else
#  error Specify which type of test to do.
#endif
  }

  return 0;
}

Results with avr-gcc 4.3.0:

   text    data     bss     dec     hex filename
     30       0       0      30      1e sizetest-s-ififif.o
     28       0       0      28      1c sizetest-s-ifelse.o
     36       0       0      36      24 sizetest-s-switch.o
     98       0       0      98      62 sizetest-0-ififif.o
    102       0       0     102      66 sizetest-0-ifelse.o
    126       0       0     126      7e sizetest-0-switch.o

The considerably larger size of the switch version when unoptimized comes from 16-bit compares. It remains larger with optimization because it clumps the tests together, necessitating more branch instructions. What switch is meant for is jump tables, which becomes apparent when you have a few more cases (8 or more?). It then starts using ijmp, eliminating the multiple tests.
For execution time, ifelse is faster if you place the most common cases first, switch is faster if it can use indirect jumps (consecutive values to test against helps) and no case is more common than all others together, and ififif is the hardest to be sure about.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It might be worth noting that there is no real
issue about what the compiler is allowed to do:
It's allowed to do anything semantically
equivalent to what it was told.
The issue is what it will or is likely to do.
A switch may be compiled in the same
manner as a sequence of if's or not.
A sequence of if's may be compiled in the
same manner as an equivalent switch or not.
Some transformations are harder than others.

In any case, the most likely way to beat the
compiler is to use information it doesn't have.
You might, e.g., know that one of the cases will always apply.

I'd think at least twice before trading intelligibility for speed.

EDIT: fixed tipo, is->it

Moderation in all things. -- ancient proverb

Last Edited: Mon. Jun 2, 2008 - 01:01 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Several years ago I was working on a custom 3D renderer for a Windows app. I found that the use of an "else" actually slowed things down considerably. By reworking the code to not use any "else" statements (at least in time critical code), I got a significant speed up in the code. That was of course specific to that compiler at the time.

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It's common that branches are costly; an if/else block turns into something like test, conditional branch, then-block, unconditional branch, else-block. Without the else, it's merely test, conditional branch, then-block. So you wind up with guaranteed branching if you have multiple ways to go. Of course, the order of these may be reversed; you can give some compilers (including GCC) "likely" hints. On AVRs, branches aren't terribly expensive as the pipeline is very short, but still good to avoid; also keeping the then-block short can be of interest, as it may be able to use a Skip instead of Branch if it's just one instruction.
Still, be sure you need it before optimising at this level.