Come spunto di riflessione ... nel caso in cui uno potrebbe essere bloccato con un compilatore vecchio/bacato/inefficiente o semplicemente l'amore per l'hacking.
Il lavoro interno di switch
è composto da due parti. Trovare l'indirizzo per saltare e saltare bene lì. Per la prima parte è necessario utilizzare una tabella per trovare l'indirizzo. Se il numero di casi aumenta, la tabella diventa più grande - la ricerca dell'indirizzo per saltare richiede tempo. Questo è il punto in cui i compilatori cercano di ottimizzare, combinando diverse tecniche, ma un approccio semplice è quello di utilizzare direttamente la tabella che dipende dallo spazio dei valori del caso.
In un retro dell'esempio tovagliolo;
switch (n) {
case 1: foo(); break;
case 2: bar(); break;
case 3: baz(); break;
}
con tale pezzo di compilatore codice può creare una matrice di jump_addresses e direttamente ottenere l'indirizzo mediante array [n]. Ora la ricerca ha appena preso O (1). Ma se si ha un interruttore come di seguito:
switch (n) {
case 10: foo(); break;
case 17: bar(); break;
case 23: baz(); break;
// and a lot other
}
compilatore deve generare una tabella contenente case_id, coppie jump_address e il codice per la ricerca in quella struttura, che con la peggiore applicazione può richiedere O (n). (I compilatori decenti ottimizzano il tutto da questo scenario quando sono completamente liberati attivando le rispettive bandiere di ottimizzazione in modo tale che quando è necessario eseguire il debug di questo codice ottimizzato il cervello inizia a friggere.)
Quindi la domanda è puoi farlo tutto te stesso a livello C per battere il compilatore? e la cosa divertente è che durante la creazione di tabelle e la ricerca attraverso di loro sembra facile, saltando a un punto variabile utilizzando goto
non è possibile in standard C. Quindi c'è una possibilità che se non si intende utilizzare i puntatori di funzione a causa di sovraccarico o struttura del codice, sei bloccato ... beh se non stai usando GCC
. GCC ha una funzione non standard denominata Labels as Values che consente di ottenere i puntatori alle etichette.
Per completare l'esempio è possibile scrivere il secondo switch con "etichette come valori" caratteristica del genere:
const void *cases[] = {&&case_foo, &&case_bar, &&case_baz, ....};
goto *labels[n];
case_foo:
foo();
goto switch_end;
case_bar:
bar();
goto switch_end;
case_baz:
baz();
goto switch_end;
// and a lot other
switch_end:
Naturalmente se si sta parlando di circa 5000 casi, è molto meglio se si scrive un pezzo di codice per creare questo codice per te - ed è probabilmente solo un modo per mantenere tale software.
Come note di chiusura; migliorerà il tuo lavoro quotidiano? No. Questo migliorerà le tue abilità? Sì e parlando per esperienza, una volta mi sono trovato a migliorare un algoritmo di sicurezza in una smart card semplicemente ottimizzando i valori dei casi. È un mondo strano.
Perché dovresti confrontare 5000 casi? Non puoi comprimere/rifattare il codice in modo da ottenere meno casi in ogni segmento di codice? – mmoment
Puoi usare un ** array di puntatori di funzioni **, è molto più veloce di qualsiasi confronto, ma la mia domanda è ... come puoi ** gestire e mantenere ** il codice con un'istruzione 'switch/case' con 5000 casi ? –
Se è necessario passare da 5000 casi, sembra un cattivo intento di progettazione. Altrimenti, andrei anche per i puntatori di funzione. – dtech