Switch case mi if else mi?

K.Makise

Kilopat
Katılım
28 Kasım 2020
Mesajlar
4.799
Makaleler
4
Çözümler
81
Daha fazla  
Cinsiyet
Erkek
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?
 
Yanlış bilgi
Switch case derleme zamanında çalışan bir yapıdır. Yani işlemci durum karşılaştırması yapmaz kod derlenirken işlemciye hangi koşullara atlaması gerektiği söylenir ve bu çalışma zamanında değiştirilemez. İf Else ise çalışma zamanında karşılaştırma yapan bir yapıdır. İşlemci koşullar oluşmuş mu oluşmamış mı teker teker kontrol eder.
 
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.
 
Cevaplar için teşekkürler.
 
Ş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.
Ş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.

C:
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;
}

C:
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;
}

Şimdi de aynı sırayla my_func() fonksiyonun x86 assembly karşılıklarını atayım. (Not: gcc -O3 flagleriyle)

Kod:
0000000000001140 <my_func>:
    1140:    f3 0f 1e fa              endbr64
    1144:    b8 67 00 00 00           mov    $0x67,%eax
    1149:    c3

Kod:
0000000000001140 <my_func>:
    1140:    f3 0f 1e fa              endbr64
    1144:    b8 67 00 00 00           mov    $0x67,%eax
    1149:    c3

Gördüğünüz üzere ortaya çıkan makine kodu tamamen aynı. Hatta değerlerin stack'teki konumları bile tamamen aynı. Compiler optimize ederken if-else bloğunu da switch bloğunu da direkt derleme aşamasında değerlendirerek sonucu eax register'ına yollamış. Kodunuz yeterince basitse hangisini kullandığınızın performans açısından önemi yok yani.

Şimdi bir de a değişkenini scanf'le almayı deneyelim. Compiler'a switch ve if bloklarını derleme aşamasında değerlendirme imkanı sunmayalım yani. Tam kodları çok uzamasın diye paylaşmayacağım çünkü iki fonksiyonda da yalnızca unsigned int a = 100; kısmını aşağıdakiyle değiştirdim. Yine gcc ve -O3 flag'ıyla derledim.

C:
int a;
printf("Value a: ");
scanf("%d", &a);

x86 Assembly kodları da bunlar:

Kod:
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>

Kod:
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>

Gene hiçbir şey değişmedi. Sonuç yine aynı yere çıkıyor. Performans farkını düşünüyorsanız compiler optimizasyonları yüzünden bazı durumlarda hiçbir şey fark etmeyecektir. Dolayısıyla kod okunurluğu açısından hangisi daha doğruysa onu kullanmak gerekir. Benim şahsi tercihim Switch-Case yapısını kullanmaktır. Daha kompleks ve performansın fark edebileceği yapılar için iki yolla da performans ve bellek kullanımı testi yapmak, test sonuçlarına göre hangisi işinize daha çok yarıyorsa onu kullanmak gerekir. Aşırı performans kritik uygulamalar yazmıyorsanız, kaybedeceğiniz birkaç nano saniye önemsizse yine kod okunurluğuna dikkat ederek kullanacağınız yapıyı seçmenizi tavsiye ederim.

Edit: Kaynak göstermeyen bir link buldum, onu da atayım.


Burada şöyle bir yorum var:
 
Son düzenleme:
@Bay kaynağı nedir o bilginin? Derleme zamanında bilinmeyen şeyler koysak ne yapacak? Derleme hatası mı verecek?
Ben burada derleme zamanına dair bir şeyden bahsedildiğini görmüyorum.

Buradaki linkten faydalanarak derleyicinin bazı Switch case durumlarını direkt derleme zamanında derlediği ve sadece atlamalar yaptığını söyleyenlerin olduğunu görebilirsiniz. Bu durum da derleyiciden derleyiciye değişiyor sanırsam. Ayrıca Buradaki linkten ilgili paragrfı çevirirseniz derlemeden önce kesin bilinen ifadeler yazmanız gerektiğini görebilirsiniz. Hatalı bilgi verdiysem af ola.
 
Bu siteyi kullanmak için çerezler gereklidir. Siteyi kullanmaya devam etmek için çerezleri kabul etmelisiniz. Daha Fazlasını Öğren.…