main
{
init();
while(1)
{
}
}
init()
{
state = 0;
swtich(state)
{
case 0 : state = 1; break;
case 1 : state = 2; break;
...
}
}
Case 1 işlenir mi ? yoksa 0 işlenip state 1 yapılsa bile break olduğu için döngü biter mi ?
İşlenmez. Yani kod case 1: içine girmez, init'ten çıkıp yoluna devam eder.
fonksiyondan çıkarsın. 1 işletilmez
Denedim işlenmiyormuş.Teşekkürler.
bu yapının aynısı VB de de var
orda "select case" şeklinde
yalnız bende case ler çok fazla yaklaşık 50 tane
benim merak ettiğim acaba uygun yani o an aranan case 'i bulana kadar
mesela ben o anda diyelim case "z" arıyorum
"z" yi bulana kadar "a" "b" "c" ..... hepsini tarıyor mu ?
çünkü benim programda bir interpreter çalışıyor yani sürekli komut satırlarını tarayıp uygun case i çalıştırıyor
ve bilgisayar çok yavaşlıyor
bu arada bendeki sürüm VB 6.0
@magnetron Evet tahminimce tarıyordur.Çünkü yazılım akışı yukarıdan aşağıya doğru olduğundan sizin z yi bulabilmesi için hepsine sıra ile bakması lazım.Daha performanslı bir kullanım için değerlerinizin ayır edici bir özelliği olması gerekir.Belki farklı algoritmalar vardır.
Mesela
void yiyecekBul(yiyecek)
{
switch(yiyecekler)
{
case meyveler:
switch(meyve)
{
case elma: break;
case armut: break;
}
break;
case sebzeler:
switch(sebze)
{
case domat: break;
case pattes: break;
}
break;
}
}
void yiyecekBul(yiyecek)
{
switch(yiyecekler)
{
case elma: break;
case armut: break;
case domat: break;
case pattes: break;
}
}
Komik bir örnek oldu :D
Büyük olasılıkla case sıralaman nereden başlıyorsa en üstte ondan itibaren bakıyor. Fakat şöyle bir not ekleyeyim bende buraya;
kod alanı az kaldığı için case mantığının fazla kod alanı yediğini düşünerek aynı şeyleri if else if lerle yazdığımda daha fazla kod alanı tuttuğunu bildireyim :) Yani switch case kullanımı daha az yer kapladı. Derleyici ARM GCC
Emin deyilim ama ilgili case adresini hesaplayıp direk oraya gider diye düşünüyorum.
8051 de bile dptr+a komutu vardı.
Hatta 16f819 için bir zamanlar asm yazdığım case yapısı söyle
CALL CEKBUTON
MOVF TEMP,W
ADDWF PCL,F
GOTO NORMAL_MOD ;0
GOTO AYAR_MOD ;1
GOTO EKSILT ;2
GOTO AYAR_DEGERI_GOSTER ;3
GOTO ARTIR ;4
GOTO TABLA_GOSTER ;5
GOTO AYAR_MOD_GOSTER ;6
GOTO NORMAL_MOD ;7
NORMAL_MOD ;0
CALL NORMAL_MOD_RUTINI
GOTO LOOP
AYAR_MOD ;1
CALL AYAR_MOD_GOSTER_RUTINI ;*
GOTO LOOP
EKSILT ;2
CALL EKSILT_RUTINI
GOTO LOOP
AYAR_DEGERI_GOSTER ;3
CALL AYAR_DEGERI_GOSTER_RUTINI
GOTO LOOP
ARTIR ;4
CALL ARTIR_RUTINI
GOTO LOOP
TABLA_GOSTER ;5
CALL TABLA_GOSTER_RUTINI
GOTO LOOP
AYAR_MOD_GOSTER
CALL AYAR_MOD_GOSTER_RUTINI ;6
GOTO LOOP
;7
@magnetron hocam bunun için farklı bir yöntem önereyim, fonksiyon gösterici denen bir olay var.
Bu konuda bir yazı yazmıştım: http://gokhanbeken.com/cc-fonksiyon-gostericilerifonksiyonu-adresi-ile-cagirmak (http://gokhanbeken.com/cc-fonksiyon-gostericilerifonksiyonu-adresi-ile-cagirmak)
mesela sizin case'inize 0 ila 255 arasında toplam 256 çeşit veri giriyor, bunların her birinde farklı bir fonksiyon var.
Yani şöyle:
state = 255;
swtich(state)
{
case 0 : islem0(); break;
case 1 : islem1(); break;
...
case 254 : islem254(); break;
case 255 : islem255(); break;
...
}
Yukarıdaki örnekte 255'inciyi bulana kadar bütün hepsini taramak zorunda kalacak.
Oysa aşağıdaki yapıda böyle birşeye gerek yok:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void islem0(void);
void islem1(void);
void islem2(void);
void islem3(void);
void islem4(void);
void islem5(void);
void islem6(void);
void islem7(void);
void islem8(void);
void islem9(void);
void (*fonksiyon_cagir)(void);
void* fonksiyonAdresleri[10]; //fonksiyonlarin pointer adreslerini tutan dizi
unsigned char state = 8;
int main(int argc, char *argv[]) {
//fonksiyonlarin adreslerini bir kereye mahsus diziye atiyoruz:
fonksiyonAdresleri[0]=&islem0;
fonksiyonAdresleri[1]=&islem1;
fonksiyonAdresleri[2]=&islem2;
fonksiyonAdresleri[3]=&islem3;
fonksiyonAdresleri[4]=&islem4;
fonksiyonAdresleri[5]=&islem5;
fonksiyonAdresleri[6]=&islem6;
fonksiyonAdresleri[7]=&islem7;
fonksiyonAdresleri[8]=&islem8;
fonksiyonAdresleri[9]=&islem9;
fonksiyon_cagir=fonksiyonAdresleri[state];
for(state=0;state<10;state++){
fonksiyon_cagir=fonksiyonAdresleri[state];
fonksiyon_cagir();
}
printf("\r\n");
return 0;
}
void islem0(void){printf("fonksiyon 0 \r\n");}
void islem1(void){printf("fonksiyon 1 \r\n");}
void islem2(void){printf("fonksiyon 2 \r\n");}
void islem3(void){printf("fonksiyon 3 \r\n");}
void islem4(void){printf("fonksiyon 4 \r\n");}
void islem5(void){printf("fonksiyon 5 \r\n");}
void islem6(void){printf("fonksiyon 6 \r\n");}
void islem7(void){printf("fonksiyon 7 \r\n");}
void islem8(void){printf("fonksiyon 8 \r\n");}
void islem9(void){printf("fonksiyon 9 \r\n");}
mesaj birleştirme:: 25 Ağustos 2015, 23:54:27
Bu da ekran görüntüsü
(http://s3.postimg.cc/41dwwu89v/ekran_g_r_nt_s.png)
Konu hakkında pek bilgim yok ama bana da mantıklı gelen sadogan'ın anlattığı gibi olması. Yoksa zaten switch-case kullanmak için bir neden kalmazdı, çünkü if-else daha esnek bir yapı. "Computed Goto" yöntemiyle karşılaştırma ile zaman kaybetmeden doğrudan atlama yapılabilir. Ancak, süreksiz girdilerde bu iş nasıl yapılıyor onu aklımda canlandıramadım. Mesela case'ler 1, 2, 3 değil de 23, 45, 100 olsa acaba tablo boş mu bırakılıyor yoksa başka bir yöntem mi var? Boş tablo bilgisayarda sorun olmaz ama belleği sınırlı gömülü sistemler için iyi bir yaklaşım olmaz.
ASM yazımda bu işlemi JMP tabloları ile yapıyoruz ve bu tablolarda Jump adresini seçen girdiler birbirini takip edecek veriler olmak zorunda.
Biz sadece en son adresin ötesinde değer gelip gelmediğini test ediyoruz. Değer bu değerden küçükse jmp tablsundan sıçramaya izin veriyoruz.
Programı yazarken buna dikkat ediyoruz. Eğer dinamik bir tablo olmayacaksa yani jmp adresleri program içinde değiştirilmeyecekse tabloları ramda değil romda tutuyoruz.
@Gökhan hocam
C 'de function pointer var - kullanıyorum da
ama ilk mesajda belirttiğim gibi bana VB 6.0 da lazım
hocam ben kavrayamadım tam istediğinizi, biraz daha açık yazarmısınız ?
(select case in daha efektif bir halini mi arıyorsunuz vb de ? )
@muhittin hocam
diyelim VB 6.0 'da şöyle bir kodumuz var
Select Case var
Case "A"
-----------------
Case "B"
------------------
Case "C"
-----------------
-----------------
-----------------
-----------------
Case "Z"
------------------
End Select
bu select case kodunu kısaltmalardan oluşan
bir text dosyası çalıştırıyor
mesela şöyle
A ... buraya bir parametre giriyor ve "A" case'i bu parametreyi alıp onunla bişey yapıyor
C ...
Z ...
Y ...
G ...
J ...
M ...
END
PLC 'lerin STL dilini biliyorsanız onun gibi bişey
bu text dosyası sürekli bir şekilde baştan sona işleniyor
işte problem burda başlıyor
benim tahminin VB 6.0 text dosyasından her satırı alıp
select case kodunun içinde o satırdaki emir "A" veya "H" veya "Y" neyse
onu arıyor
işte benim tahminim "A" emrini hemen buluyor "Y" emrini bulmak için
bütün select case kodunu sonuna kadar tarıyor
bu da bilgisayarı çok yavaşlatıyor
250 - 300 satırlık bu text dosyasını işlerken en baba Intel core işlemci bayılıyor
saniyede 20 scan 'e düşüyor
ben de bu tartışmayı görünce bu problemi sormak istedim
VB 6.0 da buna bir çare var mı diye
yani C dilindeki @Gökhan hocamın bahsettiği function pointer gibi
Doğrudan çözüm olmasa bile C dilinde yazılmış bir DLL işinizi görecektir.
Ben işlemciyi yoracak her işi C dilinde yazdığım DLL ile yaparım. Pointer ihtiyacı olan projelerde de aynısını yaparım.
Düzeltme: Her ne kadar debug yaparken aşağıdaki cümleyi doğrulayacak şeylerle karşılaşsam da;
c de switch case her case değeri için tarama yapmıyor.Switch içine girdikten sonra ilgili case değerine zıplıyor.
Şimdi baktığımda söylediğimin aksiymiş;
http://www.cagataycebi.com/programming/c_programming/c_programming_4.html (http://www.cagataycebi.com/programming/c_programming/c_programming_4.html)
şimdi switch yada select çalışmasında bir farklılık yok,
aranan değer bulunduğunda yapılması istenen yapılır ve ve select yada switch den çıkılır. ama bu arama işlemi 300 çeşitşe ve en sondaysa en sona kadar gitmek zorundadır. hiç bukadar uzun selectlerim olmadı (zaten pekde kullanmam açıkcası) ama olsa ne yapardım, düşünelim.
mesaj birleştirme:: 26 Ağustos 2015, 23:13:21
sql ve veritabanı biliyormusunuz hocam ?
300 kayıtlı basit bir veritabanı hazırlarım, doğrudan çekerim
aslında vb.net kullansanız veritabanını ram de de oluşturabilirsiniz (dataset,XML)
Successful Approximation Register yapısına bir göz at.
256 seçenek olsun. En fazla 8... bilemedin 12 karşılaştırma ile şak diye ilgili hedefe gidebilirsin.
Derleyiciler genelde siwtch/case için jump table oluşturmayı tercih eder. Böylece verilen parametre ile index hesaplayarak direkt offsete sıçrar. Yani oturup acaba gelen a mı B mi diye bakmaz. Çünkü switch yapısındaki durum programcı açısından görecelidir. İşlemci açısından kıyaslama ihtiyacı doğuran bir yapısı yoktur.
Renesas HEW'ın derleyicisi tek tek karşılaştırmayı tercih ediyor:
29 switch(command){
FE2516 39FC MOV.W -4H[FB],R0
FE2518 DA24 JEQ FE253DH
FE251A E991 CMP.W #1H,R0
FE251C DA64 JEQ FE2581H
FE251E E992 CMP.W #2H,R0
FE2520 9A04 JNE FE2525H
FE2522 CEA700 JMP.W FE25CAH
FE2525 E993 CMP.W #3H,R0
FE2527 9A04 JNE FE252CH
FE2529 CEB800 JMP.W FE25E2H
FE252C E994 CMP.W #4H,R0
FE252E 9A04 JNE FE2533H
FE2530 CE0701 JMP.W FE2638H
FE2533 E995 CMP.W #5H,R0
FE2535 9A04 JNE FE253AH
FE2537 CE2501 JMP.W FE265DH
FE253A CE5701 JMP.W FE2692H
Optimizasyon en yüksek seviyedeyken de durum aynı.
@pea olabilir vardır bir bildikleri demek ki. Diğer derleyiciler nasıl yapıyor birkaç örnek ile bakalım
x86 - Derleyici Bilinmiyor
jmp ds:off_10071F28[eax*4] ; switch jump
...
...
align 4
off_10071F28 dd offset loc_10071D4A ; jump table for switch statement
dd offset loc_10071D5B
dd offset loc_10071D67
dd offset loc_10071D89
dd offset loc_10071D95
dd offset loc_10071DA6
dd offset loc_10071DB7
dd offset loc_10071DC3
dd offset loc_10071DD4
dd offset loc_10071DE5
dd offset loc_10071E1F
...
...
...
ARMCC -O3
ER_IROM1:08009890 PUSH {R4,LR}
ER_IROM1:08009892 CMP R1, #5 ; switch 5 cases
ER_IROM1:08009894 BCS def_8009896 ; jumptable 08009896 default case
ER_IROM1:08009896 TBB.W [PC,R1] ; switch jump
ER_IROM1:08009896 ; ---------------------------------------------------------------------------
ER_IROM1:0800989A jpt_8009896 DCB 3 ; jump table for switch statement
ER_IROM1:0800989B DCB 0x10
ER_IROM1:0800989C DCB 0x13
ER_IROM1:0800989D DCB 0x16
ER_IROM1:0800989E DCB 0x19
ER_IROM1:0800989F ALIGN 2
ARMCC -O0
ER_IROM1:0800A510 PUSH {R4-R6,LR}
ER_IROM1:0800A512 MOV R6, R0
ER_IROM1:0800A514 MOV R4, R1
ER_IROM1:0800A516 MOV R5, R2
ER_IROM1:0800A518 pconn = R6 ; netconn *
ER_IROM1:0800A518 event = R4 ; netconn_evt
ER_IROM1:0800A518 len = R5 ; u16_t
ER_IROM1:0800A518 CMP event, #5 ; switch 5 cases
ER_IROM1:0800A51A BCS def_800A51C ; jumptable 0800A51C default case
ER_IROM1:0800A51C TBB.W [PC,event] ; switch jump
ER_IROM1:0800A51C ; ---------------------------------------------------------------------------
ER_IROM1:0800A520 jpt_800A51C DCB 3 ; jump table for switch statement
ER_IROM1:0800A521 DCB 0xF
ER_IROM1:0800A522 DCB 0x14
ER_IROM1:0800A523 DCB 0x19
ER_IROM1:0800A524 DCB 0x1E
ER_IROM1:0800A525 ALIGN 2
ARMv7 (Bilinmeyen Derleyici)
MCU_FLASH:08002570 028 18 F8 01 4B LDRB.W R4, [R8],#1 ; Load from Memory
MCU_FLASH:08002574 028 5B F8 04 7B LDR.W R7, [R11],#4 ; Load from Memory
MCU_FLASH:08002578 028 24 2C CMP R4, #0x24 ; switch 37 cases
MCU_FLASH:0800257A 028 00 F2 72 80 BHI.W def_800257E ; jumptable 0800257E default case
MCU_FLASH:0800257A
MCU_FLASH:0800257E 028 DF E8 04 F0 TBB.W [PC,R4] ; switch jump
MCU_FLASH:0800257E
MCU_FLASH:0800257E ; ---------------------------------------------------------------------------
MCU_FLASH:08002582 028 13 jpt_800257E DCB 0x13 ; jump table for switch statement
MCU_FLASH:08002583 028 1E DCB 0x1E
MCU_FLASH:08002584 028 1E DCB 0x1E
MCU_FLASH:08002585 028 1E DCB 0x1E
MCU_FLASH:08002586 028 1E DCB 0x1E
MCU_FLASH:08002587 028 1E DCB 0x1E
MCU_FLASH:08002588 028 1E DCB 0x1E
MCU_FLASH:08002589 028 1E DCB 0x1E
C18 (PIC18F2550)
740: switch (g_lcdinfo.index) {
19C8 0105 MOVLB 0x5
19CA 51C0 MOVF 0xC0, W, BANKED
19CC 0A05 XORLW 0x5
19CE E014 BZ 0x19F8
19D0 0A06 XORLW 0x6
19D2 E017 BZ 0x1A02
19D4 0A07 XORLW 0x7
19D6 E00B BZ 0x19EE
19D8 0A04 XORLW 0x4
19DA E004 BZ 0x19E4
19DC 0A01 XORLW 0x1
19DE E002 BZ 0x19E4
19E0 0A03 XORLW 0x3
19E2 E10F BNZ 0x1A02
XC8 (PIC18F4520)
0712 6E1F MOVWF data, ACCESS
317: {
318: switch (data)
0714 D00B BRA 0x72C
072C 501F MOVF data, W, ACCESS
072E 0AC7 XORLW 0xC7
0730 B4D8 BTFSC STATUS, 2, ACCESS
0732 D7F3 BRA 0x71A
0734 0A17 XORLW 0x17
0736 B4D8 BTFSC STATUS, 2, ACCESS
0738 D7F6 BRA 0x726
073A 0A06 XORLW 0x6
073C B4D8 BTFSC STATUS, 2, ACCESS
073E D7EB BRA 0x716
0740 0A0A XORLW 0xA
0742 B4D8 BTFSC STATUS, 2, ACCESS
0744 D7EE BRA 0x722
0746 0A01 XORLW 0x1
0748 B4D8 BTFSC STATUS, 2, ACCESS
074A D7E5 BRA 0x716
074C 0A03 XORLW 0x3
074E B4D8 BTFSC STATUS, 2, ACCESS
0750 D7E6 BRA 0x71E
0752 0A39 XORLW 0x39
0754 B4D8 BTFSC STATUS, 2, ACCESS
0756 D7E7 BRA 0x726
0758 0A17 XORLW 0x17
075A B4D8 BTFSC STATUS, 2, ACCESS
075C D7E2 BRA 0x722
075E 0A06 XORLW 0x6
0760 B4D8 BTFSC STATUS, 2, ACCESS
0762 D7DD BRA 0x71E
0764 0A0A XORLW 0xA
0766 B4D8 BTFSC STATUS, 2, ACCESS
0768 D7DC BRA 0x722
076A 0A01 XORLW 0x1
076C B4D8 BTFSC STATUS, 2, ACCESS
076E D7D5 BRA 0x71A
0770 0A03 XORLW 0x3
0772 B4D8 BTFSC STATUS, 2, ACCESS
ARM EABIv5 (Derleyici muhtemelen RVCT )
ROM1:10021A26 MOVS R3, R1 ; Rd = Op2
ROM1:10021A28 BLX $Ven$AA$L$$__ARM_switch8 ; switch 8 cases
ROM1:10021A28 ; ---------------------------------------------------------------------------
ROM1:10021A2C DCB 7
ROM1:10021A2D DCB 5, 0xA, 0xE, 0x11, 0x15, 0x1A, 0x20, 0x23 ; jump table for switch statement
ROM1:10021A35 ALIGN 2
ROM1:10021A36
ROM1:10021A36 loc_10021A36
ROM1:10021A36 MOVS R4, R2 ; jumptable 10021A28 case 0
....
Case ile ele alınacak durumlarda hız uğruna romdan çok kaybedilebilir.
0,1,2,5,10 için ya da 50 51 52 55 gibi durumlar için tablo çok mantıklı fakat
0,1,2,5,10, 60, 100, 250 için tablo çok büyür.