Как переключить 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