Рассмотрим вариант C, где операторы сравнения возвращают все биты, установленные для истинных значений, и 0 для ложных - PullRequest
0 голосов
/ 02 марта 2020

Я смотрю на вопрос и не вижу, как он будет отклоняться от нормального C. В C 1 представляет истину (конечно, любое ненулевое значение также считается истинным), а 0 представляет ложь. В каком сценарии ios вариант C будет отклоняться от традиционного C, если мы вместо этого вернем все биты, установленные, когда условия оцениваются как true. Мне кажется, что это то же самое, но я знаю, что должен быть аспект, который я не рассматриваю или просто не думаю о вопросе правильным образом. Был бы очень признателен за подсказку в правильном направлении.

Ответы [ 2 ]

3 голосов
/ 02 марта 2020

Преимущество состоит в том, что номинально выборки без ответвлений могут быть записаны более просто:

// Select c or d based on comparison of a and b.
static int Select(int a, int b, int c, int d)
{
    int mask = a < b;
    return c & mask | d & ~mask;
}

В стандарте C это может быть записано как return a < b ? c : d;, но это номинально включает тестирование a < b и затем выполнение инструкции ветвления. Инструкции ветвления часто оказывают вредное влияние на производительность процессора, и мы стараемся избегать их в высокопроизводительном коде. Поэтому вместо этого используйте битовую маску, которую можно использовать для выбора с использованием логических инструкций, а не ветвей. В некоторых случаях это может быть полезным.

Однако подобные вопросы являются гипотетическими и устаревшими. Компилятор может оптимизировать a < b ? c : d. Или, даже если использование маски лучше, возникает вопрос о том, как компилятор собирается сгенерировать ее для реализации a < b, что само по себе может включать выполнение теста и выполнение инструкции перехода, что сводит на нет преимущества. Поэтому подобные вопросы, как правило, не имеют хороших ответов в отдельности. Они служат только в контексте классной комнаты, чтобы побудить или изобразить знакомство учащихся с материалом.

1 голос
/ 03 марта 2020

Причина, по которой "ненулевой" считается true , вероятно, связана с базовой архитектурой процессора. Большинство языков ассемблера реализуют условный поток управления с помощью кодов сравнения (на x86 используется инструкция cmp, или другие инструкции неявно устанавливают флаг нуля), который устанавливает соответствующий «флаг нуля». Затем команды условного ветвления будут проверять нулевой флаг и переходить к новому местоположению, только если оно установлено.

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

Например, на машинах x86 это:

int fn(int x)
{
    if(x) return 1;
    else  return 0;
}

станет (примерно так) следующим образом:

fn:
    cmp    edi, 0
    jz    .L2

    mov    eax, 1
    ret
.L2:
    mov    eax, 0
    ret

Предположим, ваш вопрос такое "почему C рассматривает ненулевые значения как истинные?" (в этом я не был полностью уверен), причина в том, что это самый эффективный способ использовать наборы инструкций, которые мы имеем на современном оборудовании (как говорится, приведенный выше пример не нужен и неэффективен, но просто для демонстрации точка).

...