On-line: гостей 0. Всего: 0 [подробнее..]
Программисты всех стран, объединяйтесь!

АвторСообщение



ссылка на сообщение  Отправлено: 28.07.12 18:01. Заголовок: Что за зверь такой - оператор !!


Забавный вопрос встретил на одном форуме. Участник форума спрашивал, что означает оператор !!, является ли он стандартным оператором языков С/С++, или это расширение конкретного компилятора.
Этот вопрос - пример того, что можно так заработаться, что когда встречается простая, но неиспользуемая никогда в собственной практике программиста конструкция, то программист может растеряться от неожиданности.
Естественно никакого нового оператора !! в С/С++ не существует. Это конструкция представляет собой последовательное применение дважды стандартного оператора отрицания !. Почему же вызывает удивление ее наличие в коде? Дело в том, что не сразу понятен смысл ее использования, то есть а зачем это делается? Ззачем два раза подряд применяется операция отрицания?
На самом деле этот прием распространен в языке С времен стандарта С89, где отсутсвует булевый тип. Иногда требуется для значений выражений, отличных от нуля, сопоставить значение равное 1. То есть имитируется с помощью числа целого типа булевый тип, принимающий только два значения: 0 и 1.
Допустим, мы ввели определение такого булева типа. Это можно сделать по разному. Либо с помощью typedef , как, например,

typedef int bool_t;

Либо с помощью перечисления:

typedef enum { false, true } bool_t;

Однако возникает вопрос, а как сделать так, чтобы переменная нововведенного типа получала только значения равные 0 и 1?

То есть допутсим мы объявили

typedef int bool_t; 

bool_t bFlag;

int x = 10;


И хотим переменной bFlag присвоить значение либо 0, либо 1 в зависимости от того, отлично ли от нуля значение переменной x. Как это проще сделать?

Можно было бы написать

bFlag = ( x ) ? 1 : 0;


Но это довольно вычурная конструкция. Проще же на самом деле написать

bFlag = !!x;


Дело в том, что соогласно стандарту С значением операции отрицания является точно одно из двух значений: либо 0, либо 1. Поэтому когда мы первый раз применили отрицание ! к x, мы получили 0, а второе применение операции отрицания ! даст нам то, что нужно, то есть в данном конкретном случае 1.

Поэтому применение последовательно двух отрицаний !! к выражению, позволяет получить либо 1, если выражение отлично от 0, либо 0, если выражение равно 0, то есть смоделировать область значений для булева типа.




Спасибо: 0 
ПрофильЦитата Ответить
Ответов - 3 [только новые]





ссылка на сообщение  Отправлено: 28.07.12 18:02. Заголовок: Хотел бы добавить, ч..


Хотел бы добавить, что в С99 нет необходимости в использовании двойного оператора отрицания для преобразования любого выражения к целочисленному значению 0 или 1, так как в С99 введен булевой тип _Bool . На самом деле _Bool - это целочисленный беззнаковый тип, который принимает два значения 0 и 1. Любое выражение, присваиваемое переменной этого типа, преобразуется в 1, если значение выражения, стоящего справа от оператора присваивания, отлично от 0. Поэтому вместо трюка с !! в следующем примере, который уже демонстрировался выше

typedef int bool_t; 

bool_t bFlag;
int x = 10;

bFlag = !!x;


в С99 можно записать проще

 
_Bool bFlag;
int x = 10;

bFlag = x;



Спасибо: 0 
ПрофильЦитата Ответить



ссылка на сообщение  Отправлено: 28.07.12 18:04. Заголовок: Сыроежка пишет: в С..


Сыроежка пишет:

 цитата:
в С99 можно записать проще


А в новом стандарте тип _Bool исключен?

Спасибо: 0 
Цитата Ответить



ссылка на сообщение  Отправлено: 28.07.12 18:05. Заголовок: PSP пишет: А в ново..


PSP пишет:

 цитата:
А в новом стандарте тип _Bool исключен?



Тип _Bool был введен в язык С в 1999 году. Этот стандарт является текущим стандартом языка С. Хотя если следовать информации с официального сайта рабочей группы ISO/IEC, уже опубликована новая версия этого стандарта ( New revision of ISO/IEC 9899:2011 C standard (C11) published).

В С99 тип _Bool определяется как стандартный беззнаковый целочисленный тип наряду с unsigned char, unsigned short, unsigned int, unsigned long и unsigned long long. Про тип _Bool говорится, что он должен быть достаточно велик, чтобы хранить значения 0 и 1. То есть на самом деле размер типа _Bool оставлен на усмотрение разработчиков компиляторов.

В С++ имеется тип bool, которые принимает два значения false и true. И хотя в С++ тип bool также относится к целочисленным типам, _Bool и bool - это два различных типа. То есть в С++ нет ключевого слова _Bool , а в С нет ключевого слова bool.

В программах на С99 можно подключить заголовочный файл <stdbool.h>, где определяются макросы bool, true и false, которые позволяют ввести алиасы для типа _Bool и его значений 0 и 1 в стиле С++.

Замечу, что компилятор MS VC++ 2010 до сох пор не поддерживает стандарт С99 для языка С. То есть он может компилировать программы, написанные лишьь на С89.

Спасибо: 0 
ПрофильЦитата Ответить
Ответ:
1 2 3 4 5 6 7 8 9
большой шрифт малый шрифт надстрочный подстрочный заголовок большой заголовок видео с youtube.com картинка из интернета картинка с компьютера ссылка файл с компьютера русская клавиатура транслитератор  цитата  кавычки моноширинный шрифт моноширинный шрифт горизонтальная линия отступ точка LI бегущая строка оффтопик свернутый текст

показывать это сообщение только модераторам
не делать ссылки активными
Имя, пароль:      зарегистрироваться    
Тему читают:
- участник сейчас на форуме
- участник вне форума
Все даты в формате GMT  3 час. Хитов сегодня: 27
Права: смайлы да, картинки да, шрифты да, голосования нет
аватары да, автозамена ссылок вкл, премодерация откл, правка нет