Pourquoi utiliser l'opérateur ternaire sans attribuer une valeur pour la condition « true » (x = x: 1)
-
25-09-2019 - |
Question
Dans le code qemu open-source Android je suis tombé sur cette ligne de code:
machine->max_cpus = machine->max_cpus ?: 1; /* Default to UP */
Est-ce juste une façon déroutante de dire:
if (machine->max_cpus) {
; //do nothing
} else {
machine->max_cpus = 1;
}
Dans ce cas, ne serait-il plus clair que:
if (machine->max_cpus == 0) machine->max_cpus = 1;
Fait intéressant, cette compile et fonctionne très bien avec gcc, mais ne compile pas sur http: //www.comeaucomputing .com / tryitout / .
La solution
autorisé GNU une extension obscure à C
5.7 Conditionals avec Opérandes Omission
L'opérande milieu dans un conditionnel expression peut être omise. Ensuite, si le premier opérande est non nul, sa valeur est la valeur du conditionnel expression.
Par conséquent, l'expression
x ? : y
a la valeur de x est différent de zéro si cela; autrement, la valeur de y.
Cet exemple est tout à fait équivalent à
x ? x : y
Dans ce cas simple, la capacité de omettent l'opérande du milieu est pas particulièrement utile. Quand il devient utile est lorsque le premier opérande fait, ou peut (si elle est un argument macro), contenir un effet secondaire. puis répéter l'opérande au milieu serait exécuter l'effet secondaire à deux reprises. Omettre l'opérande milieu utilise la valeur déjà calculée sans effets indésirables de recalcul il.
Comme vous pouvez probablement le deviner, en évitant ce qui est recommandé pour des raisons de lisibilité et de portabilité. Je suis honnêtement surpris de voir une telle extension incompatible avec la grammaire à C.
Autres conseils
Ceci est un extension de GCC signifie " si la condition est vraie, l'utiliser, utilisez autre cette autre valeur », donc
machine->max_cpus = machine->max_cpus ?: 1;
est un raccourci pour
machine->max_cpus = machine->max_cpus ? machine->max_cpus : 1;
bien que si le conditionnel a des effets secondaires, il ne sera exécuté qu'une seule fois
En utilisant le drapeau -pedantic de gcc, il ne dit
foo.c: 5: avertissement: ISO défend C en omettant le moyen terme d'un?: expression
Il est un extension GCC , et devient plus intéressant et utile lorsque l'état a des effets secondaires.
Dans ce cas, oui, je suis d'accord pour une obscure il est plus que toute autre chose.
Le K & R BNF montre une expression est nécessaire entre "?" et ":". Je ne pense pas que gcc devrait compilera que sans diagnostic.
Il y a un autre cas utile pour cela - l'élimination des variables intermédiaires lors de l'appel d'une fonction ou d'une méthode qui pourrait revenir à zéro, que nous voulons éviter d'appeler deux fois. Par exemple (Objective-C), supposons que nous voulions décompresser un fichier dans un tableau si elle existe, sinon retourner un tableau vide.
- (NSArray*)hydrateBacklogFromFile:(NSString *path)
{
NSArray *backlog = @[];
NSData *backlogData = [NSData dataWithContentsOfFile:path];
if (backlogData)
{
backlog = [NSKeyedUnarchiver unarchiveObjectWithData:backlogData] ?: backlog;
}
return backlog;
}
Les alternatives sont moins concis.
- (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;
}
Ou plus laid avec de multiples retours etc.
- (NSArray*)hydrateBacklogFromFile:(NSString *path)
{
NSData *backlogData = [NSData dataWithContentsOfFile:path];
if (backlogData)
{
NSArray *tempArray = [NSKeyedUnarchiver unarchiveObjectWithData:backlogData];
if (tempArray != nil)
{
return tempArray;
}
}
return @[];
}
Il est donc utile de sucre syntaxique que je trouve assez lisible. Les inconvénients sont
-
La conversion implicite d'un pointeur vers un bool. Ceci est un C de longue date convention, mais la plupart des langues modernes désavouer, ce qui complique tout effort de portage.
-
Comme d'autres l'ont dit est aussi une extension non standard, il devrait donc être évitée si la portabilité est une considération du tout.