Как переключить int/_Bool в C

Предположим, что мы имеем int и хотим переключить его между 0 и 1 булевым способом. Я подумал о следующих возможностях:

int value = 0; // May as well be 1

value = value == 0 ? 1 : 0;
value = (value + 1) % 2;
value = !value; // I was curious if that would do...
  • Третий, похоже, работает. Зачем? Кто решает, что !0 есть 1?
  • Что-то не так с этим?
  • Есть ли другие возможности? например побитовые операторы?
  • Что обеспечивает лучшую производительность?
  • Было бы все, что было бы идентично с _Bool (или bool от stdbool.h)? Если нет, каковы различия?

EDIT: Много замечательных ответов с большим количеством ценной информации, спасибо! К сожалению, я могу только принять его.

Ответ 1

value = !value; выражает то, что вы хотите сделать напрямую, и делает именно то, что вы хотите сделать по определению.

Используйте это выражение.

Из C99 6.5.3.3/5 "Унарные арифметические операторы":

Результат оператора логического отрицания! 0, если значение операнд сравнивается не равным 0, 1, если значение его операнда сравнивается равный 0. Результат имеет тип int. Выражение! E эквивалентно к (0 == E).

Ответ 2

Третий, похоже, работает. Зачем? Кто решает, что это 0? 1?

C Стандарт гарантирует, что !0 1.

Есть ли другие возможности? например побитовые операторы?

Да, вы можете использовать эксклюзивный оператор OR:

value ^= 1;

Кстати, я предпочитаю это value = !value;, поскольку операторы отношения и равенства могут привести к тому, что ветвящиеся и побитовые операторы обычно этого не делают.

Ответ 3

value = !value представляется наиболее разумным, но вы также можете использовать value = 1 - value или value ^= 1. Но последние два будут разбиты, если value не 0 или 1. Первый будет работать.

Ответ 4

  • язык был разработан таким образом.
  • Используйте третий, другие правы, но излишне сложны и, следовательно, скрывают намерение.
  • value = (value ^ 1) & 1;
  • После оптимизации они все равно.
  • _Bool будет иметь те же результаты. Единственное отличие от _Bool заключается в том, что значения принудительно равны 1 или 0. Значение bool x = 55; будет иметь значение x == 1

EDIT: Исправлена ​​формула в 3 из-за моего мозга. Я даю комментарии, чтобы люди могли видеть мой blooper.

Ответ 5

В зависимости от архитектуры могут возникать заметные проблемы с производительностью:

  • ! a может потребоваться в сравнении с некоторыми архитектурами и ветвлением, что может быть дорогостоящим в зависимости от шаблона 'a'
    • на некоторых архитектурах есть условное перемещение (которое является ветвящимся), но
      который может потребовать еще 3 инструкции для завершения (с зависимостями)
  • 1 - скорее всего, потребуется две инструкции во многих архитектурах
    • Пример счетчика: ARM имеет обратное вычитание RSB% r0,% r0, # 1
  • 1 ^ a может быть реализована во многих архитектурах с одной инструкцией
  • a = (a + 1)% 2, скорее всего, будет оптимизирован для a = (a + 1) & 1, который требует 2 инструкции

Но в любом случае первое правило оптимизации - это не оптимизировать нерабочий код. Чтобы заменить! A на a ^ 1, нужно быть на 100% уверенным, что он всегда производит ожидаемое значение.

Ответ 6

Ваше выражение value = value == 0 ? 1 : 0; будет работать точно так же, как value = !value;. Вы можете использовать любой из двух.

!0 всегда 1, а также !(any non zero value) есть 0

Ответ 7

В С# вы можете использовать Math.Abs(value -1) для переключения между нулем и одним целым числом.

Ответ 8

value = 1 - value; // toggle from 0 to 1 ... or 1 to 0
                   // when you know initial value is either 0 or 1