Ich habe kürzlich ein Programm geschrieben, das ein Array sortiert. Dafür musste ich eine Vergleichsfunktion schreiben, die ich weitergeben werde. Meine Vergleichsfunktion sollte 1 (wenn x> y), -1 (wenn x <y) oder 0 (wenn x = y) zurückgegeben haben. Ich habe eine reguläre Funktion (Funktion 1) mit bedingten Ausdrücken geschrieben, aber es wurde mir empfohlen, anders zu schreiben (Funktion 2). Ist es besser so zu schreiben? Wird eine boolesche Bedingung immer 1 für die Wahrheit zurückgeben? (Ich meine, wenn x = 0 und y = 0 sind, haben wir immer (x == y) == 1?)
Funktion 1:
int Icmp(void* x, void* y)
{
int a = *(int*)x;
int b = *(int*)y;
if (a > b)
return 1;
else if (a < b)
return -1;
else
return 0;
}
Funktion 2:
int Icmp(void* x, void* y)
{
return (*(int*)x > * (int*)y) - (*(int*)x < *(int*)y);
}
Antworten:
Die bevorzugte Methode zum Schreiben des nicht verzweigten Codes wäre die Verwendung einer lokalen Variablen für die Operanden:
Der Ausdruck ist eine gängige Redewendung in Vergleichsfunktionen, und wenn er mit Variablen anstelle von In-Place-Zeiger-Dereferenzen geschrieben wird, ist er auch ziemlich lesbar.
Der Code beruht auf der Tatsache , dass das Ergebnis eines Vergleichs unter Verwendung
>
,<
oder auch==
vom Typint
und entweder 1 oder 0. Dies wird durch die C - Standard erforderlich - beliebige Compiler, der Werte , wie 42 oder -1 ist definitionsgemäß kein C - Compiler generiert .Es ist leicht zu erkennen, dass max. ein
a > b
odera < b
kann zu einem bestimmten Zeitpunkt, und das Ergebnis ist entweder wahr sein1 - 0
,0 - 1
oder0 - 0
.Warum verzweigungsloser Code? Obwohl Compiler für beide Funktionen möglicherweise genau denselben Code generieren, tun sie dies häufig nicht. Zum Beispiel scheinen sowohl das neueste GCC als auch das neueste ICC eine Verzweigung für die erste Funktion auf x86-64 zu generieren, aber verzweigungslosen Code mit bedingter Ausführung für letztere. Und an alle, die sagen, dass Filialen keine Rolle spielen, verweise ich Sie auf die am höchsten bewertete Qualitätssicherung, die jemals bei Stack Overflow durchgeführt wurde .
quelle
if
Anweisung nicht bedeutet, dass keine Verzweigung generiert wird, und dass es keine Verzweigung gibt, wenn eineif
Anweisung vorhanden ist . Es hängt in der Tat davon ab, ob der Compiler sie wegoptimieren kann.Ich würde nein sagen.
Für die Leistung; Entweder spielt es keine Rolle (wahrscheinlich für moderne Compiler), oder es sollte keine separate Funktion sein (und in den zum Sortieren verwendeten Code integriert sein), oder Sie sollten überhaupt nicht sortieren (z. B. bei der Erstellung sortierte Daten) und nicht nach der Erstellung sortiert).
Aus Gründen der Lesbarkeit (Codepflege, Möglichkeit, Fehler in der Originalversion zu sehen, Risiko, später Fehler einzuführen) würde ich Ihre Originalversion bevorzugen. besonders wenn Sie in einem Team arbeiten und besonders wenn andere Teammitglieder mit 10 anderen Programmiersprachen besser vertraut sind, für die jeweils ganz andere Regeln gelten als für C.
Speziell; Ich mag das (weil Casts im eigentlichen Code das Lesen erschweren):
..und ich würde den Rest so umschreiben, dass er so aussieht:
..oder so aussehen:
..wenn
else
nach areturn
; und weil "wenn ohne geschweifte Klammern gefolgt von einer Anweisung in der eigenen Zeile" das Risiko besteht, dass jemand versehentlich eine neue Zeile einfügt, ohne es zu merken und alles zu beschädigen (ein Beispiel finden Sie unter https://dwheeler.com/essays/apple-goto- fail.html ).quelle
Wenn Sie die Vergleichsfunktion mit verwenden
qsort
, muss die Funktion nur + ve, -ve oder Nullwerte zurückgeben.In diesem Fall können Sie die Zahlen einfach subtrahieren
quelle
(a > b) - (a < b)
, aber das Problem dabeia - b
ist, dass die Subtraktion unterlaufen kann. Dies ist also ein schlechter Ausdruck.Ganzzahlen
Schwimmt
Saiten
quelle