Frage

Was ist die Notwendigkeit für den bedingten Operator? Funktionell ist es überflüssig, da es ein if-else-Konstrukt implementiert. Wenn der Bedingungsoperator effizienter als die äquivalent if-else-Zuordnung ist, warum kann nicht if-else vom Compiler interpretiert effizienter werden?

War es hilfreich?

Lösung

Der ternäre Operator ist eine syntaktische und Lesbarkeit Bequemlichkeit, nicht eine Leistung Verknüpfung. Die Menschen sind für conditionals über die Vorteile der es aufgespalten unterschiedlicher Komplexität, aber für kurze Bedingungen kann es sinnvoll sein, einen einzeiligen Ausdruck zu haben.

Darüber hinaus, da es ein Ausdruck, wie Charlie Martin schrieb , das heißt es auf der rechten Seite erscheinen in C. eine Erklärung Dieses wertvoll für prägnante zu sein.

Andere Tipps

In C, der wirklichen Nutzen davon ist, dass es ein Ausdruck statt einer Erklärung; das heißt, können Sie es auf der rechten Seite (RHS) einer Äußerung. So können Sie prägnanter bestimmte Dinge schreiben.

Einige der anderen Antworten gegeben sind groß. Aber ich bin überrascht, dass niemand erwähnt, dass es verwendet werden kann, um const Korrektheit in einer kompakten Art und Weise durchzusetzen.

So etwas wie folgt aus:

const int n = (x != 0) ? 10 : 20;

also im Grunde n ist ein const , dessen Anfangswertes von einer Bedingung abhängig Aussage. Die einfachste Alternative ist n keine const zu machen, würde dies erlauben ein gewöhnlicher if es zu initialisieren. Aber wenn Sie es zu const wollen, kann es nicht mit einem gewöhnlichen if erfolgen. Der beste Ersatz könnten Sie wäre machen eine Hilfsfunktion wie folgt zu verwenden:

int f(int x) {
    if(x != 0) { return 10; } else { return 20; }
}

const int n = f(x);

aber die ternäre wenn Version ist wesentlich kompakter und wohl besser lesbar.

Es ist von entscheidender Bedeutung für die Code-Verschleierung, wie folgt aus:

Look->       See?!

No
:(
Oh, well
);

Die Kompaktheit und die Fähigkeit, Inline eine if-then-else in einen Ausdruck erstellen.

Es gibt eine Menge Dinge in C, die nicht technisch notwendig sind, weil sie mehr oder weniger leicht in Bezug auf andere Dinge umgesetzt werden können. Hier ist eine unvollständige Liste:

  1. , während
  2. für
  3. Funktionen
  4. structs

Stellen Sie sich vor, was Ihr Code, ohne dass diese aussehen würde, und Sie können Ihre Antwort finden. Der ternäre Operator ist eine Form von „syntaktischem Zucker“, wenn verwendet, mit Sorgfalt und Geschick macht das Schreiben und Verstehen Code einfacher.

Manchmal ist der ternäre Operator ist der beste Weg, um den Job zu erledigen. Insbesondere dann, wenn Sie das Ergebnis der ternären ein L-Wert sein.

Dies ist kein gutes Beispiel, aber ich bin ein weißer Fleck auf somethign besser zeichnen. Eine Sache ist certian, es nicht oft ist, wenn Sie wirklich brauchen die ternäre zu verwenden, obwohl ich es immer noch verwenden, um eine ganze Menge.

const char* appTitle  = amDebugging ? "DEBUG App 1.0" : "App v 1.0";

Eine Sache, die ich allerdings warnen würde gegen wird Bespannen Ternäre zusammen. Sie werden zu einem echten
Problem bei maintennance Zeit:

int myVal = aIsTrue ? aVal : bIsTrue ? bVal : cIsTrue ? cVal : dVal;

Bearbeiten : Hier ist ein potenziell besseres Beispiel. Sie können den ternären Operator verwenden Referenzen & const Werte zuweisen, wo Sie sonst eine Funktion schreiben müssen, um es zu behandeln:

int getMyValue()
{
  if( myCondition )
    return 42;
  else
    return 314;
}

const int myValue = getMyValue();

... könnte werden:

const int myValue = myCondition ? 42 : 314;

Was ist besser ist eine strittige Frage, die ich wählen, wird nicht zur Debatte.

Da niemand diese noch erwähnt, über die einzige Art und Weise intelligente printf Aussagen zu bekommen, ist die ternäre Operator zu verwenden:

printf("%d item%s", count, count > 1 ? "s\n" : "\n");

Vorab: Es gibt einige Unterschiede in Operator Vorrang, wenn Sie von C zu C ++ zu bewegen und kann durch die subtilen Fehler (n), die davon entstehen überrascht sein

.

Die Tatsache, dass der ternäre Operator ist ein Ausdruck, keine Aussage erlaubt es in der Makro-Erweiterungen für Funktionsmakros verwendet werden, die als Teil eines Ausdrucks verwendet werden. Konst nicht Teil der ursprünglichen C gewesen sein, aber der Makro Pre-Prozessor geht weit zurück.

Ein Ort, an dem ich es in einem Array-Paket, das Makros verwendet gesehen habe für abgebundenen geprüft Array zugreift. Die Syntax für eine Referenz geprüft war etwas wie aref(arrayname, type, index), wo Arrayname tatsächlich ein Zeiger auf eine Struktur, die die Arraygrenzen und ein unsigned char Array für die Daten enthalten ist, gibt die tatsächliche Art der Daten war, und die Index-Index war. Die Erweiterung dieser war ziemlich haarige (und ich werde es nicht aus dem Gedächtnis tun), aber es verwendet, um einige ternäre Operatoren die gebundene Kontrolle zu tun.

Sie können dies als Funktionsaufruf in C nicht tun, weil der Bedarf an Polymorphismus des zurückgegebenen Objekts. So wurde ein Makro benötigt, um die Typumwandlung in dem Ausdruck zu tun. In C ++ Sie können dies tun, als Templat überladenen Funktionsaufruf (wahrscheinlich für Operator []), aber C nicht über solche Funktionen.

Edit: Hier ist das Beispiel, das ich gesprochen hatte, von dem Berkeley CAD-Array-Gehäuse (glu 1.4 Ausgabe). Die Dokumentation der array_fetch Nutzung ist:

type
array_fetch(type, array, position)
typeof type;
array_t *array;
int position;
  

Fetch ein Element aus einem Array. EIN   Laufzeitfehler treten auf einem Versuch,   Referenz außerhalb der Grenzen des   Array. Es gibt keine Typüberprüfung   , dass der Wert an der gegebenen Position   tatsächlich von der Art verwendet wird, wenn   dereferencing das Array.

und hier ist das Makro Defintion von array_fetch (beachten Sie die Verwendung des ternären Operators und das Komma Sequenzierung Operators, um alle Unterausdrücke mit den richtigen Werten in der richtigen Reihenfolge als Teil eines einzigen Ausdrucks ausführen):

#define array_fetch(type, a, i)         \
(array_global_index = (i),              \
  (array_global_index >= (a)->num) ? array_abort((a),1) : 0,\
  *((type *) ((a)->space + array_global_index * (a)->obj_size)))

Die Erweiterung für array_insert (die das Array bei Bedarf wächst, wie ein C ++ Vektor) ist sogar haariger, mehrere verschachtelte ternäre Operatoren beteiligt sind.

Es sind syntaktischer Zucker und eine praktische Abkürzung für kurze if / else-Blöcke, die nur eine Anweisung enthalten. Funktionell, sollten beide Konstrukte ausführen identisch.

Ternary Betreiber von mehr Leistung sein kann als eine normale, wenn else-Klausel, diese in Embedded-Anwendungen kritisch sein kann, sondern auch Compiler-Optimierung kann diese Differenz kollabieren.

wie dwn sagte, Performance war einer der Vorteile während des Anstiegs komplexer Prozessoren, MSDN-Blog nicht-klassisches Prozessor Verhalten. Wie etwas zu tun, kann schneller sein, als es nicht zu tun ein Beispiel gibt, die den Unterschied zwischen ternären (bedingt) Betreibern klar sagt, und wenn / else-Anweisung

geben Sie den folgenden Code:

#include <windows.h>
#include <stdlib.h>
#include <stdlib.h>
#include <stdio.h>

int array[10000];

int countthem(int boundary)
{
 int count = 0;
 for (int i = 0; i < 10000; i++) {
  if (array[i] < boundary) count++;
 }
 return count;
}

int __cdecl wmain(int, wchar_t **)
{
 for (int i = 0; i < 10000; i++) array[i] = rand() % 10;

 for (int boundary = 0; boundary <= 10; boundary++) {
  LARGE_INTEGER liStart, liEnd;
  QueryPerformanceCounter(&liStart);

  int count = 0;
  for (int iterations = 0; iterations < 100; iterations++) {
   count += countthem(boundary);
  }

  QueryPerformanceCounter(&liEnd);
  printf("count=%7d, time = %I64d\n",
         count, liEnd.QuadPart - liStart.QuadPart);
 }
 return 0;
}

die Kosten für unterschiedliche Ränder sind sehr verschieden und wierd (das Originalmaterial sehen). während bei Änderung:

 if (array[i] < boundary) count++;

 count += (array[i] < boundary) ? 1 : 0;

Die Ausführungszeit ist jetzt unabhängig von dem Grenzwerte, da:

  

das Optimierungsprogramm konnte den Zweig aus dem ternären Ausdruck entfernen.

aber auf meinem Desktop Intel i5 CPU / windows 10 / vs2015, mein Tester ist ganz anders mit Msdn Blog.

bei der Verwendung von Debug-Modus , wenn / else Kosten:

count=      0, time = 6434
count= 100000, time = 7652
count= 200800, time = 10124
count= 300200, time = 12820
count= 403100, time = 15566
count= 497400, time = 16911
count= 602900, time = 15999
count= 700700, time = 12997
count= 797500, time = 11465
count= 902500, time = 7619
count=1000000, time = 6429

und ternäre Operator Kosten:

count=      0, time = 7045
count= 100000, time = 10194
count= 200800, time = 12080
count= 300200, time = 15007
count= 403100, time = 18519
count= 497400, time = 20957
count= 602900, time = 17851
count= 700700, time = 14593
count= 797500, time = 12390
count= 902500, time = 9283
count=1000000, time = 7020 

bei der Verwendung von Release-Modus , wenn / else Kosten:

count=      0, time = 7
count= 100000, time = 9
count= 200800, time = 9
count= 300200, time = 9
count= 403100, time = 9
count= 497400, time = 8
count= 602900, time = 7
count= 700700, time = 7
count= 797500, time = 10
count= 902500, time = 7
count=1000000, time = 7

und ternäre Operator Kosten:

count=      0, time = 16
count= 100000, time = 17
count= 200800, time = 18
count= 300200, time = 16
count= 403100, time = 22
count= 497400, time = 16
count= 602900, time = 16
count= 700700, time = 15
count= 797500, time = 15
count= 902500, time = 16
count=1000000, time = 16

der ternäre Operator ist langsamer, als wenn / else-Anweisung auf meinem Rechner!

so nach unterschiedlichen Compiler-Optimierungstechniken, terne Operator und wenn / sonst kann viel anders verhält.

ternäre = einfache Form des if-else. Er ist vor allem für die Lesbarkeit.

  • Einige der obskuren Operatoren in C existieren nur, weil sie die Umsetzung der verschiedenen Funktionsmakros als einzelner Ausdruck erlauben, die ein Ergebnis zurückgibt. Ich würde sagen, dass dies der Hauptzweck ist es, warum die ?: und , Betreiber existieren darf, obwohl ihre Funktionalität sonst redundant ist.

    Lassen Sie uns sagen möchten wir eine funktionsähnliche Makro implementieren, die die größte von zwei Parametern zurückgibt. Es wäre dann, wie beispielsweise genannt werden:

    int x = LARGEST(1,2);
    

    Der einzige Weg, dies zu realisieren als eine funktionsähnliche Makro wäre

    #define LARGEST(x,y) ((x) > (y) ? (x) : (y))
    

    Es wäre nicht möglich, mit einer if ... else Aussage, da es keinen Ergebniswert zurückgibt. Hinweis)

  • Der andere Zweck ?: ist, dass es tatsächlich in einigen Fällen erhöht die Lesbarkeit. Meistens ist if...else besser lesbar, aber nicht immer. Nehmen Sie zum Beispiel lange, sich wiederholende switch-Anweisungen:

    switch(something)
    {
      case A: 
        if(x == A)
        {
          array[i] = x;
        }
        else
        {
          array[i] = y;
        }
        break;
    
      case B: 
        if(x == B)
        {
          array[i] = x;
        }
        else
        {
          array[i] = y;
        }
        break;
      ...
    }
    

    Dies kann mit weit mehr lesbar ersetzt werden

    switch(something)
    {
      case A: array[i] = (x == A) ? x : y; break;
      case B: array[i] = (x == B) ? x : y; break;
      ...
    }
    
  • Bitte beachten Sie, dass ?: tut nie in schnellen Code führt als if-else. Das ist ein seltsamer Mythos von verwirrten Anfängern geschaffen. Im Fall einer optimierten Code, gibt ?: identische Leistung wie if-else in der überwiegenden Mehrheit der Fälle.

    Wenn überhaupt, ?: kann langsamer sein als if-else, weil es darum geht, mit verbindlichen impliziten Typ Aktionen, auch den Operanden, die nicht verwendet werden werden. Aber ?: kann nie als if-else schneller sein.


Hinweis) Jetzt natürlich jemand argumentieren und sich fragen, warum nicht eine Funktion verwenden. In der Tat, wenn Sie eine Funktion verwenden können, ist es immer bevorzugt über einen funktionsähnlichen Makros. Aber manchmal kann man nicht Funktionen nutzen. Nehmen wir zum Beispiel, dass in dem obigen Beispiel x wird in Dateigültigkeitsbereich deklariert. Die initializer muss dann ein konstanter Ausdruck sein, so dass es keinen Funktionsaufruf enthalten. Weitere praktische Beispiele, wo Sie haben Funktionsmakros verwenden Art sichere Programmierung mit _Generic oder „X-Makros“ einzubeziehen.

Das gleiche wie

if(0)
do();


if(0)
{
do();
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top