Tek Değer, Çok Sabit
Aynı değişkeni sabitlerle karşılaştırıp duran bir else if zinciri, C'de kendi deyimi olan bir kalıptır:
if (choice == 1) { /* ... */ }
else if (choice == 2) { /* ... */ }
else if (choice == 3) { /* ... */ }
else { /* ... */ }
switch bunu daha doğrudan söyler. İfadeyi bir kez değerlendirir, sonra doğrudan eşleşen etikete atlar.
choice'u değiştirip tekrar çalıştırın. Yapı, geçerli değerler kümesini bir bakışta görünür kılar ki burada onu tercih etmenin asıl sebebi budur.
Söz Dizimi ve case Etiketlerindeki Kurallar
switch (tamSayiIfadesi) {
case SABIT_1:
deyimler
break;
case SABIT_2:
deyimler
break;
default:
deyimler
break;
}
C'nin uyguladığı dört kısıt:
- switch ifadesinin tam sayı tipi olmalıdır -
int,char,short,longya da birenum.floatdeğil,doubledeğil ve metin değil. - Her
caseetiketi, derleme zamanında bilinen bir sabit ifade olmalıdır.n'in değişken olduğucase n:bir hatadır;case 3 + 4:vecase MAX:(bir#defineya da enum sabiti) sorunsuzdur. - İki case aynı değere sahip olamaz. Yinelenenler bir derleme hatasıdır ki bu küçük ama gerçek bir güvenlik ağıdır.
- Bir case bir aralık ifade edemez.
case 1 ... 5:standart C değil, bir GCC uzantısıdır; aralıklar için birifkullanın.
default isteğe bağlıdır ve blokta herhangi bir yerde görünebilir, ama onu sona koymak neredeyse evrensel gelenektir. default olmadan eşleşmeyen bir değer yalnızca tüm switch'i atlar.
break: Neden İsteğe Bağlı Değil
C'de switch ile ilgili tek en şaşırtıcı şey, case etiketlerinin kutular değil atlama hedefleri olmasıdır. Yürütme bir etikete indiğinde, bir break'e ya da kapanış parantezine ulaşana dek - diğer case etiketlerinin üzerinden geçerek - altındaki her deyimden geçmeye devam eder.
İlk switch bir, iki ve uc yazdırır - case 1 ile eşleşti ve sonra ondan sonraki her şeyi çalıştırdı. İkincisi yalnızca bir yazdırır. O davranışa alta düşme denir ve bir break'i unutmak klasik C switch hatasıdır: program derlenmemek yerine sessizce yanlıştır.
gcc -Wall -Wextra -Wimplicit-fallthrough ile derleyin, derleyici bir sonrakine düşen her case'i gösterir.
Son case'teki break teknik olarak gereksizdir - blok zaten orada biter. Yine de yazın, böylece sonradan altına yeni bir case eklemek sessizce bir alta düşme yaratmaz.
Kasıtlı Alta Düşme
Alta düşme, kasıtlı olduğunda bir özelliktir. Aralarında deyim olmadan etiketleri üst üste dizmek, "bu değerler aynı şeyi yapar" demenin sıradan yoludur:
Üç etiket tek bir gövdeyi paylaşır; yinelenen kod yok ve uzun bir || koşulu yok. Derleyiciler bu biçim için uyarmaz, çünkü alta düşülecek deyim yoktur.
Aralarında deyim olan alta düşme - case 1'in çalışıp sonra kasıtlı olarak case 2'ye devam etmesi - daha nadirdir ve açık bir yorumu hak eder, çünkü okuyana eksik break'in bir karar olduğunun söylenmesi gerekir:
switch (level) {
case 3:
printf("ayrintili\n");
/* fall through */
case 2:
printf("bilgi\n");
/* fall through */
case 1:
printf("hatalar\n");
break;
}
/* fall through */, GCC'nin uyarısının tanıdığı yorumdur, dolayısıyla tanı mesajını da susturur.
Karakterler Üzerinde switch
char bir tam sayı tipi olduğu için karakter sınıflandırması doğal bir uyumdur:
case 'a':'nın tek tırnak kullandığına dikkat edin - o karakterin tam sayı değerinden ibaret bir karakter sabiti. case "a": bir metin olurdu ve derlenmezdi.
Enum'lar Üzerinde switch
C'deki en iyi eşleşme, switch ile bir enum'dur. Case etiketleri okunaklı isimler olur ve derleyiciler switch her numaralandırıcıyı ele almadığında uyarabilir:
Burada kopyalamaya değer iki şey var. Her case return yapar, dolayısıyla break gerekmez - bir return fonksiyondan tamamen çıkar ki bu switch'i de bitirir. Ve default yoktur: -Wswitch ile (-Wall içinde bulunur), default'u dışarıda bırakmak, birinin beşinci bir durum ekleyip bu fonksiyonu unuttuğu gün derleyicinin uyarmasını sağlar. Bir default bunu gizlerdi.
Bir switch İçinde Değişken Bildirmek
Bir switch gövdesi tek bir bloktur, dolayısıyla bir case'teki bildirim ondan sonrakilerde görünürdür - ille de ilk değeri verilmiş olmasa da. Bir ilk değerin üzerinden atlamak C'de bir hatadır:
switch (n) {
case 1:
int x = 10; // C'de hata: bir etiket bir bildirimin önüne böyle gelemez
printf("%d\n", x);
break;
case 2:
printf("%d\n", x); // x burada var, ama hiç ilk değer almadı
break;
}
Bir case'in yerel değişkenlere ihtiyacı olduğunda onu kendi süslü parantezlerine sarın:
switch (n) {
case 1: {
int x = 10;
printf("%d\n", x);
break;
}
case 2:
printf("iki\n");
break;
}
switch mi if-else mi?
Şunların hepsi doğruysa switch'e uzanın: tek bir ifadeyi test ediyorsunuz, tam sayı tipinde ve onu sabit sabitlerle karşılaştırıyorsunuz. Menü işleme, enum durum makineleri, karakter sınıflandırması ve komut dağıtımı klasik durumlardır. Kazanç, okunabilirlik, yinelenen değer denetimi ve ele alınmamış numaralandırıcılar hakkında uyarabilen bir derleyicidir.
Testler aralıkları (score >= 90), kayan noktalı değerleri, metinleri (strcmp gerekir), birkaç farklı değişkeni ya da && ve || ile birleştirilmiş koşulları içerdiğinde if-else'e uzanın. Bunların hiçbiri bir case etiketi olarak ifade edilemez.
Başarım nadiren belirleyici etmendir. Derleyiciler yoğun bir switch'i bir atlama tablosuna, seyrek olanı karşılaştırmalara dönüştürür, dolayısıyla bir avuç case'te iki biçim ayırt edilemez. Niyeti ifade edeni seçin.
Sıkça Sorulan Sorular
C'de switch deyimi nasıl çalışır?
switch (ifade), bir tam sayı ifadesini bir kez değerlendirir, sabiti eşleşen case etiketine atlar ve oradan bir break'e ya da switch'in sonuna ulaşana dek çalışır. Hiçbir şey eşleşmezse, varsa default'a atlar; yoksa tüm bloğu atlar.
C switch'inde neden break gerekir?
Çünkü case etiketleri ayrı bloklar değil, atlama hedefleridir. break olmadan yürütme doğrudan sonraki case'in deyimlerine devam eder - buna alta düşme denir. Eksik bir break, C'deki en yaygın switch hatasıdır ve gcc -Wimplicit-fallthrough bunu işaretler.
C'de bir metin üzerinde switch yapılabilir mi?
Hayır. Bir C switch'i tam sayı ifadesi ister, dolayısıyla int, char ve enum değerleri çalışır, ama metinler, float'lar ve aralıklar çalışmaz. Bir metne göre dallanmak için bir if-else zincirinde strcmp kullanın ya da metni önce bir enum'a eşleyip onun üzerinde switch yapın.
C'de if-else yerine ne zaman switch kullanmalıyım?
Tek bir tam sayı ya da karakteri sabit bir sabitler listesiyle karşılaştırırken switch kullanın - menü komutları, enum durumları, karakter sınıflandırması. Testler aralıkları, birden fazla değişkeni ya da derleme zamanı sabitine eşitlik dışında bir şeyi içeriyorsa bir if-else zinciri kullanın.