Es gibt keinen besonderen Grund zu glauben, dass Sie etwas anderes als eine switch / case-Anweisung wünschen (und tatsächlich würde ich erwarten, dass es nicht hilfreich ist). Der Compiler sollte einen effizienten Dispatching-Code erstellen, der eine Kombination aus statischen [spärlichen] Tabellen und direkter Indizierung, binärer Verzweigung usw. beinhalten könnte; Es hat Einsichten in die statischen Werte der Fälle und sollte einen exzellenten Job machen (jedes Mal, wenn Sie die Fälle ändern, wird es spontan angepasst, während neue Werte, die nicht gut zu einem handwerklichen Ansatz passen - wie zum Beispiel stark abweichende Werte) wenn Sie eine ziemlich gepackte Array-Suche hatten - könnte eine Überarbeitung des Codes erforderlich sein oder im Hintergrund einen Speicheraufblähung oder einen Leistungsabfall verursachen.
Die Leute haben sich wirklich für diese Art von Dingen interessiert, als C versuchte, Hard-Core-Assembly-Programmierer zu gewinnen ... die Compiler wurden zur Erzeugung von gutem Code zur Rechenschaft gezogen. Anders ausgedrückt - wenn es nicht (messbar) kaputt ist, repariere es nicht.
Generell ist es toll, neugierig auf diese Art von Dingen zu sein und die Ideen der Leute zu Alternativen und ihren Auswirkungen auf die Leistung zu bekommen, aber wenn Sie wirklich interessieren und der Leistungsunterschied einen nützlichen Unterschied für Sie machen könnte Programm (vor allem, wenn Profiling es vorschlägt), dann benchmarken Sie immer mit Ihrem Programm, das wirkliche Arbeit erledigt.
Als Denkanstoß ... falls man mit einem alten / buggy / ineffizienten Compiler feststecken oder einfach nur hacken mag.
Die innere Arbeit von switch
statement besteht aus zwei Teilen. Adresse finden, um zu springen und gut dort zu springen. Für den ersten Teil müssen Sie eine Tabelle verwenden, um die Adresse zu finden. Wenn die Anzahl der Fälle zunimmt, wird die Tabelle größer - die Suche nach der Adresse benötigt Zeit. Dies ist der Punkt, den Compiler zu optimieren versuchen, indem sie mehrere Techniken kombinieren, aber ein einfacher Ansatz besteht darin, die Tabelle direkt zu verwenden, die vom Fallwertraum abhängt.
Im Hintergrund des Serviettenbeispiels;
%Vor%mit einem solchen Code-Compiler kann ein Array von jump_addresses erzeugen und die Adresse direkt nach array [n] erhalten. Jetzt hat die Suche nur O (1) genommen. Aber wenn Sie einen Schalter wie unten hatten:
%Vor%Compiler muss eine Tabelle generieren, die case_id, jump_address Paare und Code enthält, um diese Struktur zu durchsuchen, die mit der schlechtesten Implementierung O (n) annehmen kann. (Menschenwürdige Compiler optimieren die Hölle aus einem solchen Szenario, wenn sie vollständig entfesselt sind, indem sie ihre Optimierungsflags in einem Maße aktivieren, dass, wenn Sie solchen optimierten Code debuggen müssen, Ihr Gehirn anfängt zu braten.)
Dann ist die Frage: Kannst du das alles auf C-Ebene machen, um den Compiler zu schlagen? und lustige Sache ist beim Erstellen von Tabellen und die Suche durch sie scheint einfach, Springen zu einem variablen Punkt mit goto
ist nicht möglich in Standard C. So gibt es eine Chance, wenn Sie keine Funktionszeiger wegen Overhead oder Code verwenden Struktur, Sie stecken fest ... gut, wenn Sie GCC
nicht verwenden. GCC hat eine nicht standardmäßige Funktion namens Labels als Werte , mit der Sie Hinweise erhalten Etiketten.
Um das Beispiel zu vervollständigen, können Sie die zweite switch-Anweisung mit der Funktion "labels as values" wie folgt schreiben:
%Vor%Natürlich, wenn Sie über 5000 Fälle sprechen, ist es viel besser, wenn Sie einen Code schreiben, um diesen Code für Sie zu erstellen - und es ist wahrscheinlich nur eine Möglichkeit, solche Software zu pflegen.
Als Schlussnoten; Wird dies Ihre tägliche Arbeit verbessern? Nein. Wird dies Ihre Fähigkeiten verbessern? Ja, und ich habe einmal aus Erfahrung erfahren, dass ich einen Sicherheitsalgorithmus in einer Smartcard verbessert habe, indem ich einfach die Fallwerte optimiert habe. Es ist eine seltsame Welt.
Versuchen Sie, Dictionary-Klasse mit Delegate-Werten zu verwenden. Zumindest macht es Code ein wenig lesbarer.
Große switch-Anweisungen, die im Allgemeinen automatisch generiert werden, können lange dauern, um zu kompilieren. Aber ich mag die Idee, dass der Compiler die switch-Anweisung optimiert.
Eine Möglichkeit, die switch-Anweisung zu zerlegen, ist die Verwendung von Bucketing,
%Vor%Im obigen Code haben wir unsere Switch-Anweisung in 16 Teile zerlegt. Es ist einfach, die Anzahl der Buckets in automatisch generiertem Code zu ändern.
Dieser Code hat Laufzeitkosten für eine Ebene der Indirektion oder des Funktionsaufrufs hinzugefügt. . In Anbetracht der Buckets, die in verschiedenen Dateien definiert sind, ist es jedoch schneller, sie parallel zu kompilieren.
Tags und Links c c++ switch-statement