¿Por qué utilizar el operador ternario sin asignar un valor para la condición “verdadero” (x = x:? 1)
-
25-09-2019 - |
Pregunta
En el código qemu de código abierto Android me encontré con esta línea de código:
machine->max_cpus = machine->max_cpus ?: 1; /* Default to UP */
Se trata sólo de un modo confuso de decir:
if (machine->max_cpus) {
; //do nothing
} else {
machine->max_cpus = 1;
}
Si es así, ¿no sería más clara como:
if (machine->max_cpus == 0) machine->max_cpus = 1;
Curiosamente, esta compila y funciona bien con gcc, pero no se compila en http: //www.comeaucomputing .com / tryitout / .
Solución
Este es permitido en GNU como una extensión oscura a C
5,7 Conditionals con omite Operandos
El operando media en un condicional expresión puede ser omitido. A continuación, si el primer operando no es cero, su valor es el valor de la condicional expresión.
Por lo tanto, la expresión
x ? : y
tiene el valor de x si es distinto de cero; de lo contrario, el valor de y.
Este ejemplo es perfectamente equivalente a
x ? x : y
En este caso simple, la capacidad de Omitir el operando media no es especialmente útil. Cuando se hace útil es cuando el primer operando hace, o puede (si es un argumento macro), contener un efecto secundario. A continuación, repetir el operando en medio haría realizar el efecto secundario dos veces. Omitiendo el operando utiliza la media Ya valor computado sin el efectos indeseables de recalcular a él.
Como es fácil adivinar, evitar esto se recomienda por razones de legibilidad y portabilidad. Estoy honestamente sorprendió ver una extensión tal gramática-incompatible a C.
Otros consejos
Este es un GCC extensión que significa " Si la condición es verdadera, lo utilizan, bien utilizar este otro valor", por lo que
machine->max_cpus = machine->max_cpus ?: 1;
es la abreviatura de
machine->max_cpus = machine->max_cpus ? machine->max_cpus : 1;
aunque si el condicional tiene efectos secundarios, que sólo se ejecuta una vez
El uso de la bandera -pedantic de gcc, sí dice
foo.c: 5: advertencia: prohíbe ISO C omitiendo el término medio de una?: expresión
Es un GCC extensión , y se vuelve más interesante y útil cuando la condición tiene efectos secundarios.
En este caso, sí, por mi parte, estaría de acuerdo en que es más oscura que cualquier otra cosa.
El K & R BNF muestra se requiere una expresión entre "?" y ":". No creo que gcc debe compilando que sin un diagnóstico.
Hay otro caso útil para esto - la eliminación de las variables intermedias cuando se llama a una función o un método que podría volver a cero, que deseamos evitar llamar dos veces. Por ejemplo (Objective-C), supongamos que queremos descomprimir un archivo en una matriz si es que existe, de lo contrario devuelve un array vacío.
- (NSArray*)hydrateBacklogFromFile:(NSString *path)
{
NSArray *backlog = @[];
NSData *backlogData = [NSData dataWithContentsOfFile:path];
if (backlogData)
{
backlog = [NSKeyedUnarchiver unarchiveObjectWithData:backlogData] ?: backlog;
}
return backlog;
}
Las alternativas son menos concisa.
- (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;
}
O más feo con múltiples retornos, etc.
- (NSArray*)hydrateBacklogFromFile:(NSString *path)
{
NSData *backlogData = [NSData dataWithContentsOfFile:path];
if (backlogData)
{
NSArray *tempArray = [NSKeyedUnarchiver unarchiveObjectWithData:backlogData];
if (tempArray != nil)
{
return tempArray;
}
}
return @[];
}
Así que es azúcar sintáctico útil que me resulta bastante fácil de leer. Las desventajas son
-
La conversión implícita de un puntero a un bool. Este es un C de larga data convenciones, pero más modernos lenguajes Inhabilitarla, lo que complica cualquier esfuerzo de portabilidad.
-
Como otros han dicho que es también una extensión no estándar, por lo que debe ser evitado si la portabilidad es una consideración en absoluto.