if else or switch case?

which would be faster and/or less memory? i have about 25 if else statements, i was wondering if there would be any advantage of using switch case statements instead, i dont mind the look of either, i can use both pretty well, i just dont know if one would be executed faster than the other or maybe use less memory, like the last if else statements has to wait for the first 24 to be checked, but if i did a switch case would it jump directly to the last one if it matched? or would it still check them all and then goto it?

i have about 25 if else statements, i was wondering if there would be any advantage of using switch case statements

Personally I find switch/case much easier to read and maintain, particularly if you use suitably named constants for the cases, but it is up to you.

I would hope that the compiler turns out similar efficient code for both if/else and switch/case. You don’t say what your application is doing but does absolute speed matter ?

i would imagine that with so many if statements things would be better with a nicelly organized switch case. .. but i don't really have an explanation for that. it is just intuition, or something... 8)

But a quick search here in the forum took me to another thread with has a good amount of interesting information about this subject: http://forum.arduino.cc/index.php/topic,44519.0.html You can read though it, but i think in the end they found out that actually if statements were smaller and faster on Arduino. ...but i have to tell you that i didn't read it whole, i just "jumped over it". I need to go back some other time with a bit more time!

Would love to see to what conclusion you come. I have often thought about this also... ;)

Are these if statements truly independent or is it possible that arrays could help? Or in other words, post your code.

@winner10920, Haven't seen you around in a while. I agree, post it.

I also have seen comments in the Arduino core explaining that a large if set was used over a switch because the switch apparently used SRAM ( local ).

However switch statements can be used for far more logical things than simple case matching. I'm quite happy to bet that there are many situations where a switch is the superior choice. Even though Arduinos compiler is old, GCC supports C++11 ranged switch statements, which expand its use dramatically.

A lot of times where I have employed a switch for optimization reasons, the code surrounding it changes to suit the logic. And sometimes has proven to be far more efficient regardless of the ram overhead imposed by the switch. But still, the result is a product of your design, not so much a single component used to build it.

That being said there are differences that separate the two ( that are mostly overlooked ), and can therefore be exploited differently. For instance, a switch does not implicitly give scope, an if does, however the switch can have multiple statements. If you wish to use more than a single line in an if you must explicitly give it scope using '{}'.

Conversely a switch cannot instantiate new objects without explicit scope. Whereas an if can...

if( char data = Serial.read() )
  someFunc( data );

Is equivalent to, but ( can be ) more efficient than:

char data = Serial.read();
if( data  )
  someFunc( data );

You can see a good exploitation of the switch statements lack of scope in the http://en.wikipedia.org/wiki/Duff's_device. ( its possible because all cases have the same scope as the switch itself ).

EDIT: made a small edit above.

One advantage of multiple if then else is that you have control over the execution order of the cases. E.g. option 1 occurs 80% of the time and option 2 occurs 15% of the time and the other much less.

A switch case can be compiled in at least 2 ways: - an if then else ladder (which would give similar performance) - a calculated jump which can be on average faster then if then else ladder. you need to dive in the generated assembly to see it.

Then again, only interesting if speed really matters.

Here's a snippet, sorry about the readability its the first version I kinda rushed abit so no documentation, that's kinda why I'm asking now, I'm starting over from scratch and trying to give it a little more thought and time The main goal of the code is to parse a captured serial string, which I have stored in an array. This time around I'm doubling the controlled channels and adding in more commands to alter settings of the program, I know I could get away with alot less commands to shorten it but I want it to be somewhat "idiot proof" , the main reason Im worried about speed is basically response time, I'm working on an Android app to control some Rgb lights in my car and I want it to be fast, going for instantaneous reaction to the corresponding button press on my phone Thanks for reading and Srry for any grammer error, I'm typing this up on my phone which kinda sucks lol

  if(btcount > 3){
    uint16_t tempval = 0;
    btcount = 0;
    
 Serial.print(char(btbuffer[0]));
 Serial.print(char(btbuffer[1]));
 Serial.print(char(btbuffer[2]));
 Serial.print(char(btbuffer[3]));
 Serial.println(char(btbuffer[4]));
    
    if((btbuffer[0] == 'r' || btbuffer[0] == 'R') && (btbuffer[1] == 'e' || btbuffer[1] == 'E') && (btbuffer[2] == 'd' || btbuffer[2] == 'D') && (btbuffer[3] == 'd' || btbuffer[3] == 'D')){
            analogWrite(ch1, 255); 
            analogWrite(ch2,000); 
            analogWrite(ch3,000);
            EEPROM.write(10,255);
            EEPROM.write(20,000);
            EEPROM.write(30,000); 
            goto endserial;
    } else
        if((btbuffer[0] == 'b' || btbuffer[0] == 'B') && (btbuffer[1] == 'l' || btbuffer[1] == 'L') && (btbuffer[2] == 'u' || btbuffer[2] == 'U') && (btbuffer[3] == 'e' || btbuffer[3] == 'E')){
            analogWrite(ch1, 000); 
            analogWrite(ch2,000); 
            analogWrite(ch3,255);
            EEPROM.write(10,000);
            EEPROM.write(20,000);
            EEPROM.write(30,255); 
            goto endserial;
    } else
        if((btbuffer[0] == 'g' || btbuffer[0] == 'G') && (btbuffer[1] == 'r' || btbuffer[1] == 'R') && (btbuffer[2] == 'e' || btbuffer[2] == 'E') && (btbuffer[3] == 'n' || btbuffer[3] == 'N')){
            analogWrite(ch1, 000); 
            analogWrite(ch2,255); 
            analogWrite(ch3,000);
            EEPROM.write(10,000);
            EEPROM.write(20,255);
            EEPROM.write(30,000);   
            goto endserial;
    } else
    if((btbuffer[0] == 'p' || btbuffer[0] == 'P') && (btbuffer[1] == 'u' || btbuffer[1] == 'U') && (btbuffer[2] == 'r' || btbuffer[2] == 'R') && (btbuffer[3] == 'p' || btbuffer[3] == 'P')){
            analogWrite(ch1, 200); 
            analogWrite(ch2,000); 
            analogWrite(ch3,100);
            EEPROM.write(10,200);
            EEPROM.write(20,000);
            EEPROM.write(30,100);   
            goto endserial;
    } else
    if((btbuffer[0] == 'p' || btbuffer[0] == 'P') && (btbuffer[1] == 'i' || btbuffer[1] == 'I') && (btbuffer[2] == 'n' || btbuffer[2] == 'N') && (btbuffer[3] == 'k' || btbuffer[3] == 'K')){
            analogWrite(ch1,200); 
            analogWrite(ch2,000); 
            analogWrite(ch3,050);
            EEPROM.write(10,200);
            EEPROM.write(20,000);
            EEPROM.write(30,050);   
            goto endserial;
    } else
    if((btbuffer[0] == 'o' || btbuffer[0] == 'O') && (btbuffer[1] == 'r' || btbuffer[1] == 'R') && (btbuffer[2] == 'n' || btbuffer[2] == 'N') && (btbuffer[3] == 'G' || btbuffer[3] == 'g')){
            analogWrite(ch1, 255); 
            analogWrite(ch2,050); 
            analogWrite(ch3,000);
            EEPROM.write(10,255);
            EEPROM.write(20,050);
            EEPROM.write(30,000);   
            goto endserial;
    } else
    if(((btbuffer[0] == 'c' || btbuffer[0] == 'C') && (btbuffer[1] == 'r' || btbuffer[1] == 'R') && (btbuffer[2] == 'A' || btbuffer[2] == 'a') && (btbuffer[3] == 'Y' || btbuffer[3] == 'y')) || ((btbuffer[0] == 'f' || btbuffer[0] == 'F') && (btbuffer[1] == 'a' || btbuffer[1] == 'A') && (btbuffer[2] == 'd' || btbuffer[2] == 'D') && (btbuffer[3] == 'e' || btbuffer[3] == 'E'))){
            mode = cray; 
            craystep = 0;
           analogWrite(ch1, 0); 
           analogWrite(ch2, 0); 
           analogWrite(ch3,0);  
           Serial.println("Mode set to cray");
            goto endserial;
    } else
    if((btbuffer[0] == 'p' || btbuffer[0] == 'P') && (btbuffer[1] == 'r' || btbuffer[1] == 'R') && (btbuffer[2] == 'o' || btbuffer[2] == 'O') && (btbuffer[3] == 'g' || btbuffer[3] == 'G')){
            mode = program; 
           analogWrite(ch1, 255); 
           analogWrite(ch2, 255); 
           analogWrite(ch3, 255); 
          Serial.println("Mode set to program"); 
            goto endserial;
    } else
    if((btbuffer[0] == 'r' || btbuffer[0] == 'R') && (btbuffer[1] == 'a' || btbuffer[1] == 'A') && (btbuffer[2] == 'n' || btbuffer[2] == 'N') && (btbuffer[3] == 'd' || btbuffer[3] == 'D')){
            mode = randommode; 
          Serial.println("Mode set to random"); 
            goto endserial;
    } else


    
    tempval = btbuffer[1] - 48;
    tempval = tempval * 10;
    tempval += (btbuffer[2] - 48);
    tempval = tempval * 10;
    tempval += (btbuffer[3] - 48);
    


    if(btbuffer[0] == 'T' || btbuffer[0] == 't' || btbuffer[0] == '9'){ 
   Serial.print("haha");
  digitalWrite(ch1,1);
  delay(200);
  digitalWrite(ch2,1);
  delay(200);
  digitalWrite(ch3,1);
  delay(200);
  digitalWrite(ch1,0);
  delay(200);
  digitalWrite(ch2,0);
  delay(200);
  digitalWrite(ch3,0);
  delay(200);
  digitalWrite(ch1,1);
  delay(200);
  digitalWrite(ch2,1);
  delay(200);
  digitalWrite(ch3,1);
  delay(200);
  digitalWrite(ch1,0);
  delay(200);
  digitalWrite(ch2,0);
  delay(200);
  digitalWrite(ch3,0);
  delay(200);
    } 
    else
    if(btbuffer[0] == 'R' || btbuffer[0] == 'r' || btbuffer[0] == '1'){ 
      analogWrite(ch1, tempval);
      EEPROM.write(10,tempval);
    } 
    else
      if(btbuffer[0] == 'G' || btbuffer[0] == 'g' || btbuffer[0] == '2'){ 
        analogWrite(ch2, tempval);
        EEPROM.write(20,tempval);
      } 
      else
        if(btbuffer[0] == 'B' || btbuffer[0] == 'b' || btbuffer[0] == '3'){ 
          analogWrite(ch3, tempval);
          EEPROM.write(30,tempval);
        } 
        else
          if(btbuffer[0] == 'W' || btbuffer[0] == 'w'){ 
            analogWrite(ch1, 255); 
            analogWrite(ch2, 255); 
            analogWrite(ch3,255);
            EEPROM.write(10,255);
            EEPROM.write(20,255);
            EEPROM.write(30,255);
          } 
          else
            if(btbuffer[0] == 'O' || btbuffer[0] == 'o' || btbuffer[0] == '0') { 
              analogWrite(ch1, 0); 
              analogWrite(ch2, 0); 
              analogWrite(ch3,0);
              EEPROM.write(10,0);
              EEPROM.write(20,0);
              EEPROM.write(30,0);
              Serial.println("lights off");
            }   
           
    endserial:
    ewrites++;
    EEPROM.write(0,(ewrites & 0xFF00));
    EEPROM.write(1,(ewrites & 0x00FF));
    Serial.print("eeprom writes");
    Serial.println(ewrites);
  }

}

To the above I would add that there are dumb uses of both, but I've seen some RDC (Really Dumb Code) using a cascading if statement. The following was in an actual piece of production code I saw:

if (day == THEFIRST)
    DoThis();
else if (day == THESECOND)
   DoThat();
else if (day == THETHIRD)
   DoWhatever();

// more of the same...

else if (day == THETWENTYEIGHTH) {
   if (isLeapYear())
      DoLeapYear();
   else
      DoAlmostAtMonthsEnd();
else if (day == THETWENTYNINTH)
   DoREALLYCloseToMonthsEnd();
else if (day == THIRTHIETH)
   DoMonthsEnd();
else if (day == THIRTHYFIRST)
   DoMustBeDone();

I kid you not. On average, there would be 14 false if tests in this nightmare. This begs for a switch. I have not looked at the Gnu compiler code, but most C compilers I've used generate a jump table for a switch, which is usually pretty efficient. Anyway, for me, most of my applications are such that memory is not an issue, so I go with code readability and I think the switch wins that metric.

if((btbuffer[0] == 'p' || btbuffer[0] == 'P') && (btbuffer[1] == 'i' || btbuffer[1] == 'I') && (btbuffer[2] == 'n' || btbuffer[2] == 'N') && (btbuffer[3] == 'k' || btbuffer[3] == 'K'))Turning that into switch/case is going to be interesting.

Could you not loop through the string and capitalize all the characters then do a much more simple strcmp() between the capitalized string and the constants such as GREEN, PINK etc ? Put the constants in an array, do the comparisons in a for loop and exit when a match is found with an index to the action to be taken as a result of the match.

You will, of course, be getting rid of the gotos ........

Use of "toupper()" might be beneficial in decluttering.

AWOL: Use of "toupper()" might be beneficial in decluttering.

So would keeping the array NULL terminated and using strcmp().

Thats actually the first time I've ever used gotos , just a quick fix to a not so thought out program flow, I'm gonna definetly use a more thought out flow second time around, I usually try and stay away from strings, when I was Learning someone told me they are ram intensive, Is that true? Definitely would be alot simpler to have defined strings, extract the command string out of the array, and compare, but if using strings will slow things down I'd rather type more and have that complicated to read if statement,

When you say strings do you mean strings or Strings ? The former are null terminated arrays of chars whilst the latter are objects wrapping strings. Both take up RAM, but there are ways to ameliorate that when using strings, whereas Strings tend to fragment memory.

If you have a lot of choices, and the are numerical or can be represented as numerical, there are better ways to choose than either if/else or switch/case.

For example, if you state variable is s, and s can have the value 1 to 25, you could write

if ( s == 1 ) {}
else if ( s==2 ) {}
else if ( s==3 ) {}
//  et cetera

A more efficient scheme would be

if ( s < 13 )
{
    if ( s < 6 )
    {
        if ( s < 3 )
        {
        }
        else // s is 3 or higher
        {
        }
    }
    else  // s is 6 or higher
    {
    }
}
else  //  s is 13 or higher
{
}

The advantage of this is, you get to the point of knowing what to do in only 4 or 5 comparisons of s, instead of possibly 24 failed checks.

Not really numerical, the re is a part of the array that is numerical but I extract that and use it separately , and about the strings and Strings, would those commands mentioned earlier work for either or just one?

So I was under the impression (I don't know why) that this would run faster, with the code going right to the selected case. Is that not so?

switch (s){
case 0:
//
break;
case 1: 
// break;
:
case 25:
//
break;
}

If you add a null terminator to your array of chars you will turn it into a string. toupper() and strcmp() definitely work with strings. I have never used Strings but I assume that there are equivalent functions.

still not sure if switch case is better or not than if/else but just starting with the crazy compare statements how does this look? seem like itll work?

if((btbuffer[3] == 'C') && (btbuffer[4] == 'H') && (btbuffer[5] == '6') ){//original method example
            analogWrite(ch6, numberinput); 
            EEPROM.write(60,numberinput);
    } else
    if(! strcmp(commandstring, "ch5")){ // new attempt simple example
           analogWrite(ch5, numberinput); 
          EEPROM.write(50,numberinput);
    } else
//my command string is 5 char long(for now) with the null terminator so will comparing to  a shorter string work?

 if(! strcmp(commandstring, "RED")){ //comparing to three character string
//change outputs for red
} else
if(! strcmp(commandstring,"GREEN")){//comapring to full length string
//change outputs for green
}

@michinyon: If I had to maintain the code, I'd rather see 25 case blocks. Like CrossRoads, I, too, was under the impression that the Gnu compiler would generate a jump table for switch statements which would be more efficient. I'd check, but all I have is a tablet right now.

I just checked some research that Nick did and it appears that a switch-case does not always produced a jump table:

http://forum.arduino.cc/index.php?topic=178275.5;wap2

Unless I was doing some time-sensitive code where I could see that the switch-case was a problem, I'd stick with it because, for me at least, it is easier to read.