Страницы

Поиск по вопросам

вторник, 2 октября 2018 г.

Знак ! в арифметических выражениях, зачем он?

Смотрел я как то, не так давно, почти что только что, код своего преподавателя, набирался уму - разуму, да попивал чай зеленый с коньячком, и вдруг встречаю я странную штуку: k=k+!(k%2); Углубился я в раздумья - "встречал то раньше я знак восхищения только в логических выражениях, а тут вот на тебе"... И как бы я часто клавишу F10 не нажимал так понять и не смог, зачем оно и что делает. Помню, как то, человек хороший, сказал мне мудрость вот такую, что напиши ты int a=0; a следом сразу a=~a; то а в мгновенья станет -1, так вот, возможноль, что и этот случай, который был описан выше, причастен к фокусам из этих серий?


Ответ

Да, это из той же серии, что и ~a
На самом деле !a эквивалентно (a == 0) и имеет тип bool. Но когда вы интерпретируете это значение как int (а у вас так и происходит, из-за сложения с целым), bool превращается в 0 или 1. Таким образом, как целое число наше выражение эквивалентно a == 0 ? 1 : 0. В частности, если известно, что a -- 0 или 1, то это просто меняет значение на противоположное: если был ноль, станет 1, иначе станет 0.
Таким образом, выражение k+!(k%2) следует понимать так:
если k было чётным, k%2 == 0, ! обращает значение в 1, и в результате получается k+1 если k было нечётным, k%2 != 0, ! обращает значение в 0, и в результате получается просто k
То есть результат -- ближайшее (сверху) нечётное число. Makes sense?

Такая техника, как в вашем примере -- один из примеров кода, за который одни обожают, а другие ненавидят язык С++ (и С). Специалисты, тяготеющие к С, обычно больше любят такую лаконичную запись, а те, кто видит в языке скорее высокоуровневые конструкции, чем биты и байты, часто морщатся от такого кода. Я отношу себя к любителям высокоуровневых языков, но мне такие лаконичные конструкции нравятся.

Вот тут собрано много примеров подобного кода. Почитайте! Ещё несколько мозгоразрывающих примеров на SO: здесь и здесь

(Вынес из комментариев) Кстати, обратите внимание, что более коротким (и возможно более эффективным) кодом, выполняющим ту же задачу, является
k |= 1;
Он, кстати, работает и для отрицательных значений k (это не вполне очевидно).

Комментариев нет:

Отправить комментарий