Switch Case bir değer şuna eşitse bunu, buna eşitse bunu gibi işler yapmanı sağlıyor. İf else ise bir koşul sonucunda bir iş yapmanı sağlıyor. Ama sonradan switch Case a when ile şart ekleme geldi. Yani tamamen de değer kontrolü yapmıyor artık switch Case.YouTube'dan robo90 kanalının Arduino kurslarını izliyorum, az önceki Video'da Switch Case'den bahsetti ve Video'nun sonunda da bu ikisinden hangisinin daha iyi olduğunu araştırmamızı/karşılaştırmamımızı istedi.
Ben de bunu tecrübeli insanlardan öğrenmek istedim.
Tecrübe ve görüşlerinizi benimle paylaşır mısınız?
Şahsen buraya tamamen katılıyorum. Ayrıca kod okunurluğuna da dikkat etmek gerekir. Yalnız şu konuda ufak bir şey söylemem gerekir. Compiler optimizasyonları maksimumda kullanıldığında muhtemelen performans açısından hiçbir farkı yok. Bunun için aşağıya iki kod örneği atacağım ve bu kod örneklerinin assembly karşılıklarını da göstereceğim.Şahsi fikrim, seçmemek lazım. Yerine göre kullanmanız gerekiyor. Bazı yerler Switch case için uygundur, bazı yerler if else için.
unsigned int my_func()
{
int a = 100;
switch (a)
{
case 150:
a++;
break;
case 500:
a++;
a++;
break;
case 100:
a++;
a++;
a++;
break;
default:
a--;
break;
}
return a;
}
int main(void)
{
unsigned int result = my_func();
return 0;
}
unsigned int my_func()
{
unsigned int a = 100;
if (a == 150)
{
a++;
} else if (a == 500)
{
a++;
a++;
} else if (a == 100)
{
a++;
a++;
a++;
} else
{
a--;
}
return a;
}
int main(void)
{
unsigned int result = my_func();
return 0;
}
my_func()
fonksiyonun x86 assembly karşılıklarını atayım. (Not: gcc -O3 flagleriyle)0000000000001140 <my_func>:
1140: f3 0f 1e fa endbr64
1144: b8 67 00 00 00 mov $0x67,%eax
1149: c3
0000000000001140 <my_func>:
1140: f3 0f 1e fa endbr64
1144: b8 67 00 00 00 mov $0x67,%eax
1149: c3
unsigned int a = 100;
kısmını aşağıdakiyle değiştirdim. Yine gcc ve -O3 flag'ıyla derledim.int a;
printf("Value a: ");
scanf("%d", &a);
00000000000011b0 <my_func>:
11b0: f3 0f 1e fa endbr64
11b4: 48 83 ec 18 sub $0x18,%rsp
11b8: 48 8d 35 45 0e 00 00 lea 0xe45(%rip),%rsi # 2004 <_IO_stdin_used+0x4>
11bf: bf 01 00 00 00 mov $0x1,%edi
11c4: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax
11cb: 00 00
11cd: 48 89 44 24 08 mov %rax,0x8(%rsp)
11d2: 31 c0 xor %eax,%eax
11d4: e8 a7 fe ff ff call 1080 <__printf_chk@plt>
11d9: 48 8d 74 24 04 lea 0x4(%rsp),%rsi
11de: 48 8d 3d 29 0e 00 00 lea 0xe29(%rip),%rdi # 200e <_IO_stdin_used+0xe>
11e5: 31 c0 xor %eax,%eax
11e7: e8 a4 fe ff ff call 1090 <__isoc99_scanf@plt>
11ec: 8b 54 24 04 mov 0x4(%rsp),%edx
11f0: b8 97 00 00 00 mov $0x97,%eax
11f5: 81 fa 96 00 00 00 cmp $0x96,%edx
11fb: 74 1b je 1218 <my_func+0x68>
11fd: b8 f6 01 00 00 mov $0x1f6,%eax
1202: 81 fa f4 01 00 00 cmp $0x1f4,%edx
1208: 74 0e je 1218 <my_func+0x68>
120a: 8d 42 ff lea -0x1(%rdx),%eax
120d: 83 fa 64 cmp $0x64,%edx
1210: ba 67 00 00 00 mov $0x67,%edx
1215: 0f 44 c2 cmove %edx,%eax
1218: 48 8b 54 24 08 mov 0x8(%rsp),%rdx
121d: 64 48 2b 14 25 28 00 sub %fs:0x28,%rdx
1224: 00 00
1226: 75 05 jne 122d <my_func+0x7d>
1228: 48 83 c4 18 add $0x18,%rsp
122c: c3 ret
122d: e8 3e fe ff ff call 1070 <__stack_chk_fail@plt>
00000000000011b0 <my_func>:
11b0: f3 0f 1e fa endbr64
11b4: 48 83 ec 18 sub $0x18,%rsp
11b8: 48 8d 35 45 0e 00 00 lea 0xe45(%rip),%rsi # 2004 <_IO_stdin_used+0x4>
11bf: bf 01 00 00 00 mov $0x1,%edi
11c4: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax
11cb: 00 00
11cd: 48 89 44 24 08 mov %rax,0x8(%rsp)
11d2: 31 c0 xor %eax,%eax
11d4: e8 a7 fe ff ff call 1080 <__printf_chk@plt>
11d9: 48 8d 74 24 04 lea 0x4(%rsp),%rsi
11de: 48 8d 3d 29 0e 00 00 lea 0xe29(%rip),%rdi # 200e <_IO_stdin_used+0xe>
11e5: 31 c0 xor %eax,%eax
11e7: e8 a4 fe ff ff call 1090 <__isoc99_scanf@plt>
11ec: 8b 54 24 04 mov 0x4(%rsp),%edx
11f0: b8 97 00 00 00 mov $0x97,%eax
11f5: 81 fa 96 00 00 00 cmp $0x96,%edx
11fb: 74 1b je 1218 <my_func+0x68>
11fd: b8 f6 01 00 00 mov $0x1f6,%eax
1202: 81 fa f4 01 00 00 cmp $0x1f4,%edx
1208: 74 0e je 1218 <my_func+0x68>
120a: 8d 42 ff lea -0x1(%rdx),%eax
120d: 83 fa 64 cmp $0x64,%edx
1210: ba 67 00 00 00 mov $0x67,%edx
1215: 0f 44 c2 cmove %edx,%eax
1218: 48 8b 54 24 08 mov 0x8(%rsp),%rdx
121d: 64 48 2b 14 25 28 00 sub %fs:0x28,%rdx
1224: 00 00
1226: 75 05 jne 122d <my_func+0x7d>
1228: 48 83 c4 18 add $0x18,%rsp
122c: c3 ret
122d: e8 3e fe ff ff call 1070 <__stack_chk_fail@plt>
I created a small benchmark comparing switch-case to if-else-if that revealed the following (using non sequential, single byte conditions):
1. Using 4 branches and a single set of if/switch constructions:
Size: If is smaller by 24 bytes
Time: If is faster by 25%
2. Using 8 branches and a single set of if/switch constructions:
Size: If is smaller by 16 bytes
Time: Switch is faster by 24%
3. Using 4 branches and a double set of if/switch constructions:
Size: If is smaller by 42 bytes
Time: If is faster by 27%
4. Using 8 branches and a double set of if/switch constructions:
Size: If is smaller by 30 bytes
Time: Switch is faster by 27%
5. Using 5 branches and a single set of if/switch constructions:
Size: If is smaller by 10 bytes
Time: Switch is faster by 17%
Generally I would prefer switch-case for anything with 4 or more branches for readability. Apparently this is neither fastest nor smallest on the Arduino.
From 5 branches onwards, switch is faster, however at a small code size penalty.