Зачем вам использовать троичный оператор без присвоения значения для условия “true” (x = x ?:1)

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

Вопрос

В коде qemu с открытым исходным кодом Android я наткнулся на эту строку кода:

machine->max_cpus = machine->max_cpus ?: 1; /* Default to UP */

Это просто сбивающий с толку способ сказать:

if (machine->max_cpus) {
   ; //do nothing
} else {
 machine->max_cpus = 1;
}

Если да, то не было бы ли это более понятным, поскольку:

if (machine->max_cpus == 0) machine->max_cpus = 1;

Интересно, что это компилируется и отлично работает с gcc, но не компилируется на http://www.comeaucomputing.com/tryitout/ .

Это было полезно?

Решение

Это разрешенный в GNU как малоизвестное расширение к C

5.7 Условные выражения с Пропущенными операндами

Средний операнд в условном выражении может быть опущен.Тогда, если первый операнд отличен от нуля, его значением будет значение условного выражения.

Следовательно, выражение

 x ? : y

имеет значение x, если оно ненулевое;в противном случае значение y.

Этот пример прекрасно эквивалент к

 x ? x : y

В этом простом случае возможность опустить средний операнд не особенно полезна.Когда это становится полезным, это когда первый операнд выполняет, или может (если это аргумент макроса), содержать побочный эффект.Затем повторение операнда в середине привело бы к выполнению побочного эффекта дважды.При пропуске среднего операнда используется уже вычисленное значение без нежелательных последствий его повторного вычисления.

Как вы, вероятно, можете догадаться, избегать этого рекомендуется по соображениям удобочитаемости и переносимости.Я, честно говоря, удивлен, увидев такое несовместимое с грамматикой расширение для C.

Другие советы

Это Расширение GCC Это означает «если условие верно, используйте его, иначе использовать это другое значение», так

machine->max_cpus = machine->max_cpus ?: 1;

Снаряжена

machine->max_cpus = machine->max_cpus ? machine->max_cpus : 1;

Хотя, если условный имеет побочные эффекты, он будет только один раз

Использование гк -педантического флага, он говорит

foo.c: 5: Предупреждение: ISO C запрещает пропустить средний термин a?: выражение

Это Расширение GCC, и становится интереснее и полезно, когда состояние имеет побочные эффекты.

В этом случае да, я за человека согласился бы, что это неясно, что больше всего на свете.

BNF K & R показывает выражение между «?» а также ":". Я не думаю, что GCC должен быть составлен, без диагностики.

Для этого есть еще один полезный случай - устранение промежуточных переменных при вызове функции или способа, который может вернуть NIL, что мы хотим избежать вызова дважды. Например, (objective-c), предположим, что мы хотим распаковать файл в массив, если он существует, в противном случае верните пустой массив.

- (NSArray*)hydrateBacklogFromFile:(NSString *path)
{
    NSArray *backlog = @[];
    NSData *backlogData = [NSData dataWithContentsOfFile:path];
    if (backlogData)
    {
        backlog = [NSKeyedUnarchiver unarchiveObjectWithData:backlogData] ?: backlog;
    }
    return backlog;
}

Альтернативы менее лаконичны.

- (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;
}

Или уродливее с несколькими возвратами и т. Д.

- (NSArray*)hydrateBacklogFromFile:(NSString *path)
{
    NSData *backlogData = [NSData dataWithContentsOfFile:path];
    if (backlogData)
    {
        NSArray *tempArray = [NSKeyedUnarchiver unarchiveObjectWithData:backlogData];
        if (tempArray != nil)
        {
            return tempArray;
        }
    }
    return @[];
}

Так что это полезно синтаксический сахар, который я нахожу довольно читаемым. Недостатками являются

  • Неявное преобразование указателя на бул. Это давно постоянная конвенция C, но большинство современных языков запрещают его, осложняют любые усилия по переплетам.

  • Поскольку другие сказали, что это также нестандартное расширение, поэтому следует избегать, если переносимость вообще сообрабатывается.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top