¿Por qué utilizar el operador ternario sin asignar un valor para la condición “verdadero” (x = x:? 1)

StackOverflow https://stackoverflow.com/questions/2806255

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 / .

¿Fue útil?

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.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top