switch vs. if... else if. More efficient?

Greetings!

I’m programming the code for the CMUCam and serial interface right now and have just begun the portion where I determine the kind of data I am getting from the serial port buffer. I can imagine that this is an intensive process on the controller… so:

would it be more efficient to use a switch statement or an else… else if chain to determine what the next character in the buffer is?

I’ve read that a switch statement (out of many possibilities) would be more efficient because of compiler’s ability to optimize the order of comparisons. But does this apply in the case of C18 2.4?

Thank you!

The switch statement essentially constructs the same code as a stack of if/then/else statements.

The switch is useful because it is a way of documenting code and representing it as a 1 of n selector.

This is a plenty fast processor for what you are probably going to try and do so I wouldn’t worry about it.

Worrying about these types of things for your i/o routines generally isn’t necessary as it was say 30 years ago.

Always optimize for readability. The exceptions to this rule are very few and far between.

Agreed. Switch is the way to go IMO. But then again it depends on exactly what you’re doing.

documenting your code is especially important if your the sole student programmer on your team and your about to graduate :slight_smile:

if thens might give you more control in some situations, but with state comparisons and what not, switches are pretty and convenient

I’ve been on the recieving end of that situation. All the programming was done by a father/son team. They refused to “share” with any outsiders. They couldn’t make it to our regional.

I had to learn how to program the robot by reading a printout of the code in the back of a van on the way to regionals. This nightmare situation was only made worse by their need to shave a clock cycle here and there.

The switch statement essentially constructs the same code as a stack of if/then/else statements.

Its functionally equivalent code, but in my experience it is seldom literally the same. That’s because a switch statement is used with a single control variable that most often covers a packed or marginally sparse value range (that is, has a range of n…m with few if any values skipped).

In the following test you can see using an “if…else if…else if” has a worse case path of 28 instruction and takes a literal approach of comparison. An example of a single test is shown below:

058A6 D00A BRA 0x58bc
235: else if (data_type == 11)
058A8 0EFE MOVLW 0xfe
058AA 50DB MOVF 0xfdb, W, ACCESS
058AC 080B SUBLW 0xb
058AE E104 BNZ 0x58b8

Whereas the switch statement uses a different approach in the compiler with all the comparisons up front and uses about 1/2 as many instruction cycles worse case. The more elements in the “if…else if…” sequence, the more efficient the switch generated code is (at least within the C 2.4 compiler).


240:               	switch (data_type)
 058BC    0EFE     MOVLW 0xfe
 058BE    50DB     MOVF 0xfdb, W, ACCESS
 058C0    0A0B     XORLW 0xb
 058C2    E01A     BZ 0x58f8
 058C4    0A02     XORLW 0x2
 058C6    E015     BZ 0x58f2
 058C8    0A01     XORLW 0x1
 058CA    E010     BZ 0x58ec
 058CC    0A0B     XORLW 0xb
 058CE    E00B     BZ 0x58e6
 058D0    0A01     XORLW 0x1
 058D2    E006     BZ 0x58e0
 058D4    0A03     XORLW 0x3
 058D6    E001     BZ 0x58da
 058D8    D012     BRA 0x58fe
241:               	{

Still other compilers will use a program jump table strategy to get the switch/case down to 4-8 cycles (compiler aligns a jump table on a 256 program word boundary and uses the switch variable to goto the appropriate entry in the table which then does a goto to the specific code entry.

However, both “if…else if…” and switch are good and valid methods without significant difference except for possible readability. The only place it would really matter would be if the code is executed at interrupt level – then you might be more concerned with code efficiency vs readability.


221:               void test_ifswitch( unsigned char data_type )
 05852    CFD9     MOVFF 0xfd9, 0xfe6
 05854    FFE6     NOP
 05856    CFE1     MOVFF 0xfe1, 0xfd9
 05858    FFD9     NOP
222:               {
223:               static char counter;
224:               
225:                if (data_type == 1)
 0585A    0EFE     MOVLW 0xfe
 0585C    04DB     DECF 0xfdb, W, ACCESS
 0585E    E104     BNZ 0x5868
226:                 counter = 1;
 05860    0105     MOVLB 0x5
 05862    0E01     MOVLW 0x1
 05864    6F68     MOVWF 0x68, BANKED
227:                else if (data_type == 2)
 05866    D02A     BRA 0x58bc
 05868    0EFE     MOVLW 0xfe                                ; if the compiler was "smart", it would realize
 0586A    50DB     MOVF 0xfdb, W, ACCESS               ; the W reg contains data_type-1, therefore
 0586C    0802     SUBLW 0x2                                 ; it would need to just -1 to test for == 2 
 0586E    E104     BNZ 0x5878                                 ; and save two instruction cycles and be closer
                                                                         ; switch code efficiency... but alas
228:                 counter = 2;
 05870    0105     MOVLB 0x5
 05872    0E02     MOVLW 0x2
 05874    6F68     MOVWF 0x68, BANKED
229:                else if (data_type == 3)
 05876    D022     BRA 0x58bc
 05878    0EFE     MOVLW 0xfe
 0587A    50DB     MOVF 0xfdb, W, ACCESS
 0587C    0803     SUBLW 0x3
 0587E    E104     BNZ 0x5888
230:                 counter = 3;
 05880    0105     MOVLB 0x5
 05882    0E03     MOVLW 0x3
 05884    6F68     MOVWF 0x68, BANKED
231:                else if (data_type == 8)
 05886    D01A     BRA 0x58bc
 05888    0EFE     MOVLW 0xfe
 0588A    50DB     MOVF 0xfdb, W, ACCESS
 0588C    0808     SUBLW 0x8
 0588E    E104     BNZ 0x5898
232:                 counter = 8;
 05890    0105     MOVLB 0x5
 05892    0E08     MOVLW 0x8
 05894    6F68     MOVWF 0x68, BANKED
233:                else if (data_type == 9)
 05896    D012     BRA 0x58bc
 05898    0EFE     MOVLW 0xfe
 0589A    50DB     MOVF 0xfdb, W, ACCESS
 0589C    0809     SUBLW 0x9
 0589E    E104     BNZ 0x58a8
234:                 counter = 9;
 058A0    0105     MOVLB 0x5
 058A2    0E09     MOVLW 0x9
 058A4    6F68     MOVWF 0x68, BANKED
235:                else if (data_type == 11)
 058A6    D00A     BRA 0x58bc
 058A8    0EFE     MOVLW 0xfe
 058AA    50DB     MOVF 0xfdb, W, ACCESS
 058AC    080B     SUBLW 0xb
 058AE    E104     BNZ 0x58b8
236:                 counter = 11;
 058B0    0105     MOVLB 0x5
 058B2    0E0B     MOVLW 0xb
 058B4    6F68     MOVWF 0x68, BANKED
237:                else
 058B6    D002     BRA 0x58bc
238:                 counter = -1;
 058B8    0105     MOVLB 0x5
 058BA    6968     SETF 0x68, BANKED
239:               
240:                switch (data_type)
 058BC    0EFE     MOVLW 0xfe
 058BE    50DB     MOVF 0xfdb, W, ACCESS
 058C0    0A0B     XORLW 0xb
 058C2    E01A     BZ 0x58f8
 058C4    0A02     XORLW 0x2
 058C6    E015     BZ 0x58f2
 058C8    0A01     XORLW 0x1
 058CA    E010     BZ 0x58ec
 058CC    0A0B     XORLW 0xb
 058CE    E00B     BZ 0x58e6
 058D0    0A01     XORLW 0x1
 058D2    E006     BZ 0x58e0
 058D4    0A03     XORLW 0x3
 058D6    E001     BZ 0x58da
 058D8    D012     BRA 0x58fe
241:                {
242:                 case 1: counter = 1; break;
 058DA    0E01     MOVLW 0x1
 058DC    6F68     MOVWF 0x68, BANKED
 058DE    D010     BRA 0x5900
243:                 case 2: counter = 2; break;
 058E0    0E02     MOVLW 0x2
 058E2    6F68     MOVWF 0x68, BANKED
 058E4    D00D     BRA 0x5900
244:                 case 3: counter = 3; break;
 058E6    0E03     MOVLW 0x3
 058E8    6F68     MOVWF 0x68, BANKED
 058EA    D00A     BRA 0x5900
245:                 case 8: counter = 8; break;
 058EC    0E08     MOVLW 0x8
 058EE    6F68     MOVWF 0x68, BANKED
 058F0    D007     BRA 0x5900
246:                 case 9: counter = 9; break;
 058F2    0E09     MOVLW 0x9
 058F4    6F68     MOVWF 0x68, BANKED
 058F6    D004     BRA 0x5900
247:                 case 11: counter = 11; break;
 058F8    0E0B     MOVLW 0xb
 058FA    6F68     MOVWF 0x68, BANKED
 058FC    D001     BRA 0x5900
248:                 default: counter = -1;
 058FE    6968     SETF 0x68, BANKED
249:                }
250:               }
 05900    52E5     MOVF 0xfe5, F, ACCESS
 05902    CFE7     MOVFF 0xfe7, 0xfd9
 05904    FFD9     NOP
 05906    0012     RETURN 0