Warum würden Sie verwenden, um den ternären Operator ohne einen Wert für den „wahren“ Zustand zuweisen (x = x: 1)
-
25-09-2019 - |
Frage
In dem Android Open-Source-Code qemu ich auf dieser Codezeile lautete:
machine->max_cpus = machine->max_cpus ?: 1; /* Default to UP */
Ist das nur eine verwirrende Art zu sagen:
if (machine->max_cpus) {
; //do nothing
} else {
machine->max_cpus = 1;
}
Wenn ja, wäre es nicht klarer sein als:
if (machine->max_cpus == 0) machine->max_cpus = 1;
Interessanterweise ist diese kompiliert und funktioniert gut mit gcc, aber nicht kompiliert auf http: //www.comeaucomputing .com / tryitout / .
Lösung
Dies ist erlaubt in GNU als eine obskure Erweiterung auf C
5.7 Conditionals mit weggelassenen Operanden
Der mittlere Operanden in einem bedingten Ausdruck kann weggelassen werden. Dann, wenn die erster Operand ungleich Null ist, sein Wert ist der Wert der bedingten Ausdruck.
Daher ist der Ausdruck
x ? : y
hat den Wert von x, wenn das nicht Null ist; andernfalls wird der Wert von y.
Dieses Beispiel ist vollkommen gleichwertig zu
x ? x : y
In diesem einfachen Fall die Fähigkeit, omit der mittlere Operand nicht besonders nützlich. Wenn es wird nützlich ist, wenn der erste Operand der Fall ist, oder kann (wenn es sich um eine Makro-Argument ist), enthält eine Nebenwirkung. dann Wiederholung der Operand in der Mitte würde zuführen zweimal den Nebeneffekt. Das Weglassen des mittleren Operand verwendet die Wert bereits ohne die berechneten unerwünschte Wirkungen von recomputing es.
Wie Sie wahrscheinlich erraten kann, dies zu vermeiden ist, um die Lesbarkeit und Portabilität Gründen empfohlen. Ich bin überrascht, ehrlich, eine solche Grammatik-inkompatiblen Erweiterung C sehen
Andere Tipps
Dies ist ein GCC-Erweiterung das bedeutet " wenn die Bedingung erfüllt ist, verwenden sie es, sonst diesen anderen Wert verwenden“, so
machine->max_cpus = machine->max_cpus ?: 1;
ist eine Abkürzung für
machine->max_cpus = machine->max_cpus ? machine->max_cpus : 1;
obwohl, wenn die bedingten Nebenwirkungen hat, wird es nur einmal ausgeführt werden
Mit gcc -pedantic Flagge, es sagt
foo.c: 5: Warnung: ISO C verbietet die mittlere Laufzeit von einem Weglassen?: Ausdruck
Es ist eine GCC Erweiterung , und es wird mehr interessant und nützlich, wenn die Bedingung Nebenwirkungen hat.
In diesem Fall ja, denn ich würde man zustimmen es ist unklar mehr als alles andere.
Die K & R BNF zeigt ein Ausdruck erforderlich, um zwischen "?" und ":". Ich glaube nicht, gcc sollte ohne Diagnose, dass kompilieren.
Es gibt einen weiteren nützlichen Fall für diese - die Eliminierung von Zwischenvariablen, wenn eine Funktion oder eine Methode aufrufen, die Null zurückkehren könnte, dass wir zweimal Aufruf vermeiden wollen. Zum Beispiel (Objective-C) an, dass wir eine Datei in eine Array entpacken wollen, wenn es vorhanden ist, sonst ein leeres Array zurück.
- (NSArray*)hydrateBacklogFromFile:(NSString *path)
{
NSArray *backlog = @[];
NSData *backlogData = [NSData dataWithContentsOfFile:path];
if (backlogData)
{
backlog = [NSKeyedUnarchiver unarchiveObjectWithData:backlogData] ?: backlog;
}
return backlog;
}
Die Alternativen sind weniger prägnant.
- (NSArray*)hydrateBacklogFromFile:(NSString *path)
{
NSArray *backlog = @[];
NSData *backlogData = [NSData dataWithContentsOfFile:path];
if (backlogData)
{
NSArray *tempArray = [NSKeyedUnarchiver unarchiveObjectWithData:backlogData];
if (tempArray != nil)
{
backlog = tempArray;
}
}
return backlog;
}
oder hässlicher mit mehreren kehrt etc.
- (NSArray*)hydrateBacklogFromFile:(NSString *path)
{
NSData *backlogData = [NSData dataWithContentsOfFile:path];
if (backlogData)
{
NSArray *tempArray = [NSKeyedUnarchiver unarchiveObjectWithData:backlogData];
if (tempArray != nil)
{
return tempArray;
}
}
return @[];
}
So ist es sinnvoll syntaktischer Zucker ist, dass ich ziemlich lesbar zu finden. Die Nachteile sind
-
Die implizite Konvertierung eines Zeigers auf einem Bool. Dies ist eine seit langem bestehende C Konvention, aber die meisten modernen Sprachen verbieten es, verkompliziert kein Portierungsaufwand.
-
Wie schon andere gesagt haben, es ist auch eine Nicht-Standard-Erweiterung, so sollte es vermieden werden, wenn Portabilität eine Überlegung überhaupt ist.