использование логических значений в c

<p>c не имеет встроенных логических типов. какой лучший способ использовать их в c?</p>

<p>от лучшего к худшему:</p><p><strong>вариант 1 (c99)</strong></p><pre><code>#include <stdbool.h> </code></pre><p><strong>вариант 2</strong></p><pre><code>typedef enum { false, true } bool; </code></pre><p><strong>вариант</strong></p><pre><code>typedef int bool; enum { false, true }; </code></pre><p><strong>вариант 4</strong></p><pre><code>typedef int bool; #define true 1 #define false 0 </code></pre><h1>объяснение</h1><ul> <li>вариант 1 будет работать, только если вы используете c99, и это "стандартный способ" сделать это. выберите это, если это возможно.</li> <li>варианты 2, 3 и 4 будут иметь на практике одинаковое поведение. # 2 и # 3 не используют #defines, что, на мой взгляд, лучше.</li> </ul><p>если вы не определились, идите с # 1!</p>

<p>несколько мыслей о логических значениях в c:</p><p>я достаточно взрослый, чтобы просто использовать обычные <code>int</code>s в качестве моего логического типа без каких-либо определений типов, специальных определений или перечислений для значений true/false. если вы последуете моему предложению никогда не сравнивать с булевыми константами, тогда вам все равно нужно будет использовать 0/1 для инициализации флагов. однако такой подход может считаться слишком реакционным в эти современные времена. в этом случае определенно следует использовать <code><stdbool.h></code>, поскольку он, по крайней мере, имеет преимущество от стандартизации.</p><p>какие бы булевы константы ни назывались, используйте их только для инициализации. никогда не пиши что-то вроде</p><pre><code>if (ready == true) ... while (empty == false) ... </code></pre><p>они всегда могут быть заменены на более четкие</p><pre><code>if (ready) ... while (!empty) ... </code></pre><p>обратите внимание, что они могут быть разумно и понятно прочитаны вслух.</p><p>дайте вашим логическим переменным положительные имена, т.е. <code>full</code> вместо <code>notfull</code>. последнее приводит к коду, который трудно прочитать легко. сравнить</p><pre><code>if (full) ... if (!full) ... </code></pre><p>с</p><pre><code>if (!notfull) ... if (notfull) ... </code></pre><p>обе из первой пары читаются естественным образом, в то время как <code>!notfull</code> читать неловко, как есть, и становится намного хуже в более сложных логических выражениях.</p><p>обычно следует избегать логических аргументов. рассмотрим функцию, определенную следующим образом</p><pre><code>void foo(bool option) { ... } </code></pre><p>в теле функции очень ясно, что означает аргумент, поскольку он имеет удобное и, мы надеемся, значимое имя. но сайты вызова выглядят так</p><pre><code>foo(true); foo(false): </code></pre><p>здесь, по сути, невозможно сказать, что имел в виду параметр, не всегда просматривая определение или объявление функции, и становится намного хуже, как только вы добавляете еще больше логических параметров. я предлагаю либо</p><pre><code>typedef enum { opt\_on, opt\_off } foo\_option; void foo(foo\_option option); </code></pre><p>или же</p><pre><code>#define opt\_on true #define opt\_off false void foo(bool option) { ... } </code></pre><p>в любом случае сайт вызова теперь выглядит так</p><pre><code>foo(opt\_on); foo(opt\_off); </code></pre><p>который читатель, по крайней мере, имеет шанс понять, не углубляясь в определение <code>foo</code>.</p>

<p>логическое значение в c является целым числом: ноль для false и ненулевое значение для true.</p><p>смотрите также <a href="https://en.wikipedia.org/wiki/boolean\_data\_type#c.2c\_c.2b.2b.2c\_objective-c.2c\_awk"><em> логический тип данных </em>, раздел <em> c, c++, objective-c, awk </em></a> .</p>

<p>вот версия, которую я использовал:</p><pre><code>typedef enum { false = 0, true = !false } bool; </code></pre><p>поскольку ложь имеет только одно значение, но логическое истина может иметь много значений, но метод устанавливает истину так, чтобы компилятор использовал ее в противоположность ложному.</p><p>это решает проблему того, что кто-то кодирует что-то, что сводится к этому</p><pre><code>if (true == !false) </code></pre><p>я думаю, что мы все согласны с тем, что это не очень хорошая практика, но за единовременную стоимость выполнения операции "true =! false" мы устраняем эту проблему.</p><p>[редактировать] в конце концов я использовал:</p><pre><code>typedef enum { myfalse = 0, mytrue = !myfalse } mybool; </code></pre><p>чтобы избежать конфликта имен с другими схемами, которые определяли <code>true</code> и <code>false</code>. но концепция остается прежней.</p><p>[edit] чтобы показать преобразование целого числа в логическое значение:</p><pre><code>mybool somebool; int someint = 5; somebool = !!someint; </code></pre><p>первый (самый правый)! преобразует ненулевое целое число в 0, затем второе (самое левое)! преобразует значение 0 в значение <code>myfalse</code>. я оставлю читателю в качестве упражнения преобразование нулевого целого числа.</p>

<p>если вы используете компилятор c99, он имеет встроенную поддержку типов bool:</p><pre><code>#include <stdbool.h> int main() { bool b = false; b = true; } </code></pre><p> <a href="https://en.wikipedia.org/wiki/boolean\_data\_type#c.2c\_c.2b.2b.2c\_objective-c.2c\_awk">http://en.wikipedia.org/wiki/boolean\_data\_type</a> </p>

<pre><code>typedef enum { false = 0, true } t\_bool; </code></pre>

<p>обо всем по порядку. c, то есть iso/iec 9899 имеет логический тип в течение <strong> 19 лет </strong>. это намного больше времени, чем <a href="https://en.wikipedia.org/wiki/expected\_value">ожидаемая</a> продолжительность карьеры программиста на c с любительской/академической/профессиональной частью, объединенной при посещении <strong> этого вопроса </strong>. моя превосходит это всего лишь на 1-2 года. это означает, что за то время <strong>, которое средний читатель узнал вообще о c, c фактически имел логический тип данных </strong>.</p><p>для типа данных <code>#include <stdbool.h></code> и используйте <code>true</code>, <code>false</code> и <code>bool</code>. или не включайте его и используйте вместо него <code>\_bool</code>, <code>1</code> и <code>0</code>.</p><hr><p>в этой ветке ответов есть различные <strong> опасные </strong> советы. я обращусь к ним:</p><pre><code>typedef int bool; #define true 1 #define false 0 </code></pre><p>это нет-нет, потому что случайный читатель, который изучал c в течение этих 19 лет, мог ожидать, что <code>bool</code> ссылается на <strong> фактический </strong> <code>bool</code> тип данных и будет вести себя так же, но это не так! например</p><pre><code>double a = ...; bool b = a; </code></pre><p>с c99 <code>bool</code>/<code>\_bool</code>, <code>b</code> будет установлен на <code>false</code> <strong>, если </strong> <code>a</code> был равен нулю, а <code>true</code> в противном случае. при наличии <code>typedef</code> <code>double</code> будет приведено к <code>int</code> - если значение типа double не находится в диапазоне для <code>int</code>, поведение <strong> не определено </strong>.</p><p>естественно, то же самое относится к случаям, когда <code>true</code> и <code>false</code> были объявлены в <code>enum</code>.</p><p>что еще <strong> более опасно </strong> объявляет</p><pre><code>typedef enum bool { false, true } bool; </code></pre><p>потому что теперь <strong> все значения </strong>, кроме 1 и 0, недопустимы, и если такое значение будет присвоено переменной этого типа, <strong> поведение будет полностью неопределенным </strong>.</p><p>поэтому <strong> если </strong> вы не можете использовать c99 по какой-то необъяснимой причине, для логических переменных вы должны использовать:</p><ul> <li>введите <code>int</code> и значения <code>0</code> и <code>1</code> <strong> как есть </strong>; и тщательно выполняйте преобразования доменов из любых других значений в них с двойным отрицанием <code>!!</code></li> <li>или если вы <strong> настаиваете </strong>, то вы не помните, что 0 - это ложь и ненулевое значение, по крайней мере используйте <strong> регистр </strong>, чтобы они не путались с концепциями c99: <code>bool</code>, <code>true</code> и <code>false</code>!</li> </ul>

<p>c имеет логический тип: <strong>bool</strong> (по крайней мере, за последние 10 (!) лет)</p><p>включите stdbool.h, и true/false будет работать как положено.</p>

<p>все, что не равно нулю, оценивается как истинное в логических операциях, так что вы можете просто</p><pre><code>#define true 1 #define false 0 </code></pre><p>и использовать константы.</p>

<p>@thomas matthews: условные выражения считаются истинными, если они ненулевые, но стандарт c требует, чтобы сами логические операторы возвращали либо 0, либо 1.</p><p>@tom: #define true! false - это плохо и совершенно бессмысленно. если заголовочный файл попадает в скомпилированный код c++, то это может привести к проблемам:</p><pre><code>void foo(bool flag); ... int flag = true; foo(flag); </code></pre><p>некоторые компиляторы генерируют предупреждение о преобразовании int => bool. иногда люди избегают этого, делая:</p><pre><code>foo(flag == true); </code></pre><p>заставить выражение быть c++ bool. но если вы #define true! false, вы получите:</p><pre><code>foo(flag == !0); </code></pre><p>который заканчивает тем, что делает сравнение типа int-to-bool, которое может в любом случае вызвать предупреждение.</p>

<p>вы можете использовать символ или другой контейнер с небольшим числом для него.</p><p><strong>псевдо-код</strong></p><pre><code>#define true 1 #define false 0 char bvalue = true; </code></pre>

<p>вот это:</p><pre><code>#define true 1 #define false 0 </code></pre>

<p>просто дополнение к другим ответам и некоторым разъяснениям, если вам разрешено использовать c99.</p><pre><code>+-------+----------------+-------------------------+--------------------+ | name | characteristic | dependence in stdbool.h | value | +-------+----------------+-------------------------+--------------------+ | \_bool | native type | don't need header | | +-------+----------------+-------------------------+--------------------+ | bool | macro | yes | translate to \_bool | +-------+----------------+-------------------------+--------------------+ | true | macro | yes | translate to 1 | +-------+----------------+-------------------------+--------------------+ | false | macro | yes | translate to 0 | +-------+----------------+-------------------------+--------------------+ </code></pre><p>некоторые из моих предпочтений:</p><ul> <li><code>\_bool</code> или <code>bool</code>? оба в порядке, но <code>bool</code> выглядит лучше, чем ключевое слово <code>\_bool</code>.</li> <li>допустимые значения для <code>bool</code> и <code>\_bool</code>: <code>false</code> или <code>true</code>. назначение <code>0</code> или <code>1</code> вместо <code>false</code> или <code>true</code> допустимо, но сложнее для чтения и понимания логического потока.</li> </ul><p>некоторая информация из стандарта:</p><ul> <li><code>\_bool</code> не является <code>unsigned int</code>, но входит в группу <em>целочисленные типы без знака</em>. он достаточно большой, чтобы содержать значения <code>0</code> или <code>1</code>.</li> <li>не, но да, вы можете переопределить <code>bool</code> <code>true</code> и <code>false</code>, но это не очень хорошая идея. эта способность считается устаревшей и будет удалена в будущем.</li> <li>присвоение <em>скалярного типа</em> (арифметических типов и типов указателей) <code>\_bool</code> или <code>bool</code>, если значение <em>скалярного</em> равно <code>0</code> или сравнивается с <code>0</code>, это будет <code>0</code>, в противном случае результат is <code>1</code>: <code>\_bool x = 9;</code> <code>9</code> преобразуется в <code>1</code> при назначении <code>x</code>.</li> <li><code>\_bool</code> составляет 1 байт (8 бит), обычно программист испытывает искушение попытаться использовать другие биты, но это не рекомендуется, потому что дается только один гарантированный, что для хранения данных используется только один бит, а не тип <code>char</code>, который есть 8 бит доступны.</li> </ul>

<p>вы можете использовать \_bool, но возвращаемое значение должно быть целым числом (1 для true, 0 для false). однако рекомендуется включать и использовать bool, как в c++, как сказано в <a href="https://www.daniweb.com/posts/jump/1057160">этот ответ</a> из <a href="https://www.daniweb.com">форум daniweb</a> , а также <a href="https://stackoverflow.com/a/4767954/9034686">этот ответ</a> из этот другой вопрос stackoverflow:</p><blockquote> <p>\_bool: логический тип c99. использование \_bool напрямую рекомендуется только в том случае, если вы поддерживаете устаревший код, который уже определяет макросы для bool, true или false. в противном случае эти макросы стандартизированы в заголовке. включите этот заголовок, и вы можете использовать bool, как в c++.</p> </blockquote>