Подтвердить что ты не робот

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

В коде 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/.

4b9b3361

Ответ 1

Это разрешено в GNU как неясное расширение до C

5.7 Условные обозначения с опущенными операндами

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

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

 x ? : y

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

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

 x ? x : y

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

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

Ответ 2

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

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

является сокращением для

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

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

Ответ 3

Используя gcc -pedantic flag, он говорит

foo.c: 5: предупреждение: ISO C запрещает опустив средний член a: Выражение

Ответ 4

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

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

Ответ 5

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

Ответ 6

Для этого есть еще один полезный случай: устранение промежуточных переменных при вызове функции или метода, которые могут возвращать нуль, что мы хотим избежать вызова дважды. Например (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 @[];
}

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

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

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