Когда переменная bool не true и не false одновременно
Недавно читали код и наткнулись на примерно такой такой фрагмент.
bool *t = new bool[X][Y]; // много строк switch (t[M][N]) < case true: // много строк break; case false: // много строк break; default: // много строк break; >
Сразу возникает вопрос: зачем нужна ветка default? Если переменная не равна true, то она равна false. Однокурсник сказал: «Для отладки». Думаю: что тут можно отлаживать? Но не всё так просто.
Запускаю. Выполняется код в ветке default. Самое первое предположение — забыли поставить break. Внимательно перечитываю код — всё в порядке. Запускаю в отладчике и замечаю, что выполняется сразу ветка default, а в ветку true или false даже не заходит. Решаю просмотреть значение переменной. Visual Studio 2012 запущенная на Windows 7 показывает 205. Допустим. Плюсы я стал учить недавно, поэтому решил провести небольшой опыт: создал булевую переменную и присвоил ей 205. Отрабатывает ветка true. Пока я размышлял над этой проблемой, однокурсник нашёл решение этой проблемы: оказывается, массив не был инициализирован. После инициализации проблема исчезла. Теперь у меня возник возник вопрос: неужели проблема в switch? Ради проверки я решил провести следующий опыт.
#include using namespace std; int main() < bool *t = new bool[1]; switch (t[0]) < case true: cout if(t[0] == true) < cout else if(t[0] == false) < cout else < cout if(t[0]) < cout else if(!t[0]) < cout else < cout delete[] t; return 0; >
Вариант с switch или первый вариант с if позволяет определить не инициализированную булевую переменную. Второй вариант с if никогда не заходит в третий вариант.
Как создать такую переменную Шрёдингера? Создайте динамический или статический массив. Используйте его перед инициализацией. А также, самое вкусное, то, что вы можете скопировать это неопределённое значение, даже в скалярную переменную. Где это может пригодится — решать вам.
Интересно также то, что если перед проверкой вставить:
char a = t[0]; t[0] = a;
то переменная наконец-то станет true. А если написать
bool a = t[0]; t[0] = a;
то ничего не изменится.
Позднее я повторил опыт на Visual Studio 2013 с 5 пакетом обновления запущенная на Windows 7. Там отладчик говорит, что неинициализированная переменная равна true, но несмотря на это в блок true не заходит. Также она говорит, что ветка default не нужна, так как все возможные метки уже заданы. Но несмотря на это заходит в блок default.
В Linux данная особенность не проявляется.
- Ненормальное программирование
- C++
тип bool в C
Не могу понять, что происходит с типом bool. пустая прога:
при компиляции gcc выдает:
test.c: in function ‘main’: test.c:3: ‘bool’ undeclared (first use in this function) test.c:3: (Each undeclared identifier is reported only once test.c:3: for each function it appears in.) test.c:3: parse error before ‘bval’
Что, нет такого типа ‘bool’.
CyberCoder ★
28.02.03 23:14:43 MSK
Re: тип bool в C
Прикинь, и в самом деле нет.
anonymous
( 01.03.03 00:03:01 MSK )
Re: тип bool в C
Типа bool в С действительно нет. Точнее, в версиях стандарта до C99 его действительно нет. В С99 он есть, но называется _Bool. Кроме того, определен заголовочный файл в котором определен `bool’ как синоним для _Bool. Сделано это было, чтобы не нарушать совместимость с существующим кодом. GCC поддерживает С99 в этом отношении. Однако особого смысла в использовании _Bool/bool я не вижу, т.к. в плане проверки типов это обычный целочисленный тип (совместимый по присваиванию с int и так далее). Единственная особенность — явное приведение к _Bool дает всегда либо 0 либо 1 (это, однако, не означает, что переменная типа _Bool будет занимать в памяти один бит) — точно такой же эффект может быть достигнут при помощи `!!’
aa5779 ★
( 01.03.03 01:47:58 MSK )

Re: тип bool в C
А не проще писать так?
#define TRUE 1
#define FALSE 0
Ну и для полной радости
typedef unsigned short bool;
OxiD ★★★★
( 01.03.03 13:27:18 MSK )
Ответ на: Re: тип bool в C от OxiD 01.03.03 13:27:18 MSK
Re: Re: тип bool в C
short занимает 2 байта, может быть вместо него использовать char?
CyberCoder ★
( 01.03.03 14:48:37 MSK ) автор топика
Re: тип bool в C
Компилятор при сравнениях и прочих операциях будет приводить char к int, так что ты выиграешь (может быть) в памяти, но проиграешь (какие-то копейки) в скорости.
Конструкция
typedef enum bool;
будет лучше (IMHO), чем #define.
nobody ★★
( 01.03.03 15:10:04 MSK )
Ответ на: Re: тип bool в C от nobody 01.03.03 15:10:04 MSK
Re: Re: тип bool в C
я понял, спасибо за ответы
CyberCoder ★
( 01.03.03 15:30:16 MSK ) автор топика

Re: тип bool в C
Oxid ты уверен что 0 - это false? мне кажется что должно быть что то типа #define TRUE (1 == 1) #define FALSE (!TRUE) typedef enum bool; может не прокатить в конструкции while (!false) < /* XXX */ >т.к. enum не обязан начинаться с 0 да и я не уверен что 0 это на самом деле false
lg ★★
( 02.03.03 11:19:32 MSK )
Re: тип bool в C
Ну здрасьте, всегда в условиях проверяли числа и указатели на 0 просто if(!number) а тут оказывается false!=0. приехали.
anonymous
( 02.03.03 17:00:58 MSK )
Re: тип bool в C
> enum не обязан начинаться с 0
Согласно стандарту языка Си, первый элемент перечисления по умолчанию равен 0.
> я не уверен что 0 это на самом деле false
Если использовать конструкцию
enum ;
то слово false будет синонимом числа 0.
Во всяком случае, компилятор, встретив false, будет заменять его на 0 (а true — на 1).
Тип у обоих будет int.
Вот пример:
Функция, написанная программером:
bool fn(bool arg)
<
if (arg) do_something();
else do_nothing();
return true;
>
Та же функция, но с точки зрения компилятора:
int fn(int arg)
<
if (arg != 0) do_something();
else do_nothing();
return 1;
>
Вобщем, разница между использованием int в диапазоне от 0 до 1 и использованием bool от false до true заключается только в читабельности программы. Если в программе есть немалое количество функций, возвращающих только успешность выполнения (да/нет), то есть смысл (IMHO) использовать для этих целей bool — для лучшей читаемости. То же самое справедливо и для аргументов функций.
nobody ★★
( 02.03.03 17:50:01 MSK )
Re: тип bool в C
Плохо не то что false == 0, а то что true == 1; Значит проверки на x == true будут проваливаться для большинства случаев.
В C нет булевского типа — лучше с этим смириться и вести себя соответсвенно, а не смущать народ.
anonymous
( 02.03.03 19:13:19 MSK )
Re: тип bool в C
> Значит проверки на x == true будут проваливаться
> для большинства случаев
int main()
<
if (fn() != true) puts(«anonymous прав»);
return 0;
>
Если функция возвращает либо false, либо true, все будет работать.
Если функция возвращает char *, то fn() == true работать не будет.
Но то же самое верно и для Си++.
При чем здесь «В C нет булевского типа — лучше с этим смириться и вести себя соответсвенно, а не смущать народ»?
nobody ★★
( 02.03.03 21:16:00 MSK )
Re: тип bool в C
> Если функция возвращает char *, то fn() == true работать не будет.
Именно. Догадайтесь почему. (Правильный ответ — нет встроенного преобразования char* -> bool, т.к.»В C нет булевского типа» )
> Но то же самое верно и для Си++.
При чем здесь это? Кстати и в С++ bool не слишком нужен. (Я не имею в виду vector).
> При чем здесь «В C нет булевского типа — лучше с этим смириться и вести себя соответсвенно, а не смущать народ»?
Проверки типа ‘!= NULL’, ‘== FALSE’, ‘== TRUE’ в С не только бесполезны, но и вредны. Тот кто их применяет — напрашивается на неприятности сам и делает код менее читаемым для окружающих.
anonymous
( 02.03.03 21:37:36 MSK )
Re: тип bool в C
2nobody К тому же вы передергиваете. Сравните bool fn() int main() < if (fn() != true) puts("anonymous прав"); return 0; >и bool fn() < return 45; >main() < if(fn() == true) puts("nobody стопудово прав"); return 0; >(typedef enum bool; подразумевается) anonymous (*) (2003-03-02 21:37:36.281)
anonymous
( 02.03.03 22:00:04 MSK )
Re: тип bool в C
false == 0
frue == не 0 (любое число != 0)
anonymous
( 03.03.03 06:50:21 MSK )
Re: тип bool в C
Предпоследнему anonymous.
Похоже, имеет место непонимание друг друга.
Пример.
/* При успешном выполнении функция возвращает 1. */
/* При ошибке — 0. */
int fn(const char *filename)
<
if (some_condition) return 0;
/*. */
if (another_condition) return 0;
/*. */
return 1;
>
int main(int argc, char *argv[])
<
if (!fn(argv[1])) return 1;
/*. */
return 0;
>
Так вот, функция fn может в данном случае выглядеть так:
bool fn(const char *filename)
<
if (some_condition) return false;
/*. */
if (another_condition) return false;
/*. */
return true;
>
При этом отпадает необходимость такого комментария:
/* При успешном выполнении функция возвращает 1. */
/* При ошибке — 0. */
для каждой подобной функции.
Если такая функция одна, то не стоит и огород городить.
А если их два десятка, то программа (IMHO) будет читаться легче — потому что достаточно взглянуть на объявление функции в файле .h, чтобы понять, что она возвращает. Если же функция объявлена как возвращающая int, то придется лезть в файл .c, чтобы почитать комментарий — ведь функция, возвращающая int, может вернуть не только признак успешного/ошибочного выполнения, но и вообще все, что угодно — например, дескриптор открытого файла. Функция же, возвращающая bool, может вернуть только признак успешности своего выполнения — во всяком случае, так подразумевается читающим программу.
А ты в своем примере (с fn() == 45) нарушаешь общепринятые правила: объявляешь функцию так, будто она возвращает значение перечислимого типа, а на самом деле она возвращает другое.
Вот поясняющий пример:
int main()
<
static const char c[] = «123»;
putchar(c[fn()]);
puts(«segfault почему-то не случился»);
return 0;
>
nobody ★★
( 03.03.03 13:58:12 MSK )
Re: тип bool в C
> Похоже, имеет место непонимание друг друга. Да похоже. > Пример. > > /* При успешном выполнении функция возвращает 1. */ > /* При ошибке - 0. */ > int fn(const char *filename) > < >if (some_condition) return 0; > /*. */ > if (another_condition) return 0; > /*. */ > return 1; > > Не проще ли указать, что: 0 - в случае ошибки не 0 - в случае успеха. > int main(int argc, char *argv[]) > < >if (!fn(argv[1])) return 1; > /*. */ > return 0; > > Забегая вперед .Опять !fn. Если применяешь символические константы, то проверяй как fn() == false или fn() != true, иначе зачем ты их вообще определял? > Так вот, функция fn может в данном случае выглядеть так: > > bool fn(const char *filename) > < >if (some_condition) return false; > /*. */ > if (another_condition) return false; > /*. */ > return true; > > Это читается только после того как найдешь определения true и false. > При этом отпадает необходимость такого комментария: > > /* При успешном выполнении функция возвращает 1. */ > /* При ошибке - 0. */ И появляется необходимость в таком комментарии: /* При успешном выполнении функция возвращает true. */ /* При ошибке - false. */
anonymous
( 03.03.03 15:01:01 MSK )
Ответ на: Re: тип bool в C от nobody 03.03.03 13:58:12 MSK
Re: Re: тип bool в C
> Для каждой подобной функции. > Если такая функция одна, то не стоит и огород городить. > А если их два десятка, то программа (IMHO) будет читаться легче -- > потому что достаточно взглянуть на объявление функции в файле .h, > чтобы понять, что она возвращает. IMHO нет. Возвращаемые значения как раз и должны указываться в комментария в header'е. > Если же функция объявлена как возвращающая int, то придется лезть в > файл .c, чтобы почитать комментарий -- ведь функция, возвращающая > int, может вернуть не только признак успешного/ошибочного > выполнения, но и вообще все, что угодно -- например, дескриптор > открытого файла. В любом случае придется договариваться какие возвращаемые значения сигналят об ошибке. > Функция же, возвращающая bool, может вернуть только признак > успешности своего выполнения -- во всяком случае, так > подразумевается читающим программу. Разумно. > А ты в своем примере (с fn() == 45) нарушаешь общепринятые правила: > объявляешь функцию так, будто она возвращает значение перечислимого > типа, а на самом деле она возвращает другое. Странно, а компилятор мне на это не указал :( Может быть правила не такие уж общепринятые? > Вот поясняющий пример: > > typedef enum e; > > e fn() > > int main() > < >static const char c[] = "123"; > putchar(c[fn()]); > puts("segfault почему-то не случился"); > return 0; > > Segmentation fault. В Си нет диапазонных типов.
Научный форум dxdy
Последний раз редактировалось MGM 09.11.2022, 21:23, всего редактировалось 1 раз.
Алгоритм работает с BigInteger, поэтому прямое сравнение не проходит, пришлось написать простенькую функцию, сравнивающую два дробных числа:
bool equal(BQ_LTYPE a, BQ_LTYPE b) <
<>
Функция используется в следующем месте кода:
bool equ_x = equal(rct_fr[fr_i].qx, rct_fl[fl_i].qx);
bool equ_y = equal(rct_fr[fr_i].qy, rct_fl[fl_i].qy);
Первая строка сравнивает 1/6 c 1/6 и правильно выдает true .
Вторая строка сравнивает 1/5 c 1/5 и вроде бы правильно выдает true . Но в скобке дебагер дает некую цифру (204).
Самое поразительное, что оператор
Это какая-то загадка, так как 204 — если это число, по сути тоже true .
Re: true(204) в C++ что за зверь?
09.11.2022, 21:59
Последний раз редактировалось Schrodinger’s cat 09.11.2022, 22:12, всего редактировалось 6 раз(а).
В плюсах любое положительное число равно true.
А то, что такой if выдает false действительно странно.
Может приведете листинг программы предшествующий этому if. желательно со значениями в переменных (а то пока Вы это будете делать уже и ошибку отловите )
Re: true(204) в C++ что за зверь?
10.11.2022, 04:02
Последний раз редактировалось TheRuinedMap 10.11.2022, 04:05, всего редактировалось 2 раз(а).
MGM в сообщении #1569536 писал(а):
Вторая строка сравнивает 1/5 c 1/5 и вроде бы правильно выдает true . Но в скобке дебагер дает некую цифру (204).
В какой «скобке»? Где дебаггер вам это «выдает»? О чем речь?
MGM в сообщении #1569536 писал(а):
Самое поразительное, что оператор
Это какая-то загадка, так как 204 — если это число, по сути тоже true .
Что означает эта загадочная запись и какое она имеет отношение к С++?
Re: true(204) в C++ что за зверь?
10.11.2022, 05:34
Последний раз редактировалось TheRuinedMap 10.11.2022, 06:25, всего редактировалось 13 раз(а).
Schrodinger’s cat в сообщении #1569539 писал(а):
В плюсах любое положительное число равно true.
. В таком буквальном виде это утверждение неверно. Если сравнивать true с целым значением, то true будет преобразовано к значению 1 . А 1 не равно 204 . Поэтому условие true == 204 всегда гарантированно ложно .
Я примерно понимаю, что вы хотели сказать — с точностью до наоборот: в булевском контексте любое ненулевое целочисленное значение приводится к true . Однако как это относится к теме — не ясно.
MGM в сообщении #1569536 писал(а):
Но в скобке дебагер дает некую цифру (204).
Вы нас скорее всего обманываете. Ваше булевское значение не имеет никакого отношения к тем переменным, которые вы привели выше. Значение 204 в шестнадцатеричном виде — это 0xCC . Это подозрительно похоже на какой-то дебажный заполнитель для неинициализированной памяти. То есть вы смотрите на неинициализированную переменную типа bool , которая содержит «мусорное» значение.
MGM в сообщении #1569536 писал(а):
Самое поразительное, что оператор
Это какая-то загадка, так как 204 — если это число, по сути тоже true .
Нет, нет, нет, ни в коем случае. 204 в переменной типа bool — это не true .
Обращение к «мусорной» булевской переменной порождает неопределенное поведение. На практике, если ее физическое представление не совпадает с корректным представлением true или false на вашей платформе, то такая булевская переменная может вести себя и как «ни true , ни false «, так и как «и true , и false одновременно». Этот «феномен» очень часто встречается на практике и удивленными вопросами на эту тему забит весь инет. Не пытайтесь работать с неинициализированными переменными.
На вашей платформе (как и на большинстве платформ) false скорее всего физически представляется как байт 0x00 , а true — как байт 0x01 . Это значит, что 204 в bool будет вести себя непредсказуемым образом.
Вот вам небольшая программка навскидку
#include
#include
bool return_bad_bool() __attribute__((noinline));
bool return_bad_bool()
bool b;
std::memset(&b, 204, 1);
return b;
>
При компиляции GCC без оптимизаций эта программа выдает одновременно «True! False!» http://coliru.stacked-crooked.com/a/ded1d2461a7915f2
При компиляции GCC c -O3 эта программа выдает «True!» http://coliru.stacked-crooked.com/a/e8ff36833396d507
При компиляции Clang она всегда выдает «False!» http://coliru.stacked-crooked.com/a/cc113189bb73726c
Посмотрев на сгенерированный ассемблерный код, вы сможете понять, почему так происходит. Но с точки зрения языка это просто неопределенное поведение .
Вот именно это явление вы и наблюдаете в вашем if , когда пытаетесь пихать в него «мусорный» bool .
Re: true(204) в C++ что за зверь?
10.11.2022, 09:03
Последний раз редактировалось Schrodinger’s cat 10.11.2022, 09:04, всего редактировалось 1 раз.
TheRuinedMap в сообщении #1569577 писал(а):
Поэтому условие true == 204 всегда гарантированно ложно.
Согласен, но там другое условие. Там И а не Равно. Математика булева а не целочисленная.
Наоборот тоже можно изголяться бул использовать в целочисленной математике. Понятно что в нормальных программах так лучше не делать.
Целочисленные значения должны преобразовываться в бул.
Тоже подозреваю что у ТС что то с недоинициализацией, отсюда и неопределенное поведение.
Re: true(204) в C++ что за зверь?
10.11.2022, 17:08
Последний раз редактировалось MGM 10.11.2022, 17:09, всего редактировалось 1 раз.
Мне сложно как-то вразумительно объяснить.
Однако подобный вопрос был в англоязычном форуме и с моей точки зрения разрешился не по причине выясненного бага, а в следствие внесения дополнительного кода.
Цитата:
have an object called Symbol which represents a variable. Symbol has the Boolean attribute used which is initialized as false. This condition is changed to true in the event that it is called upon to solve a function to show that it was used. For some reason when Symbol is unused and used is never changed to true i t returns the value 204 instead of false
По сути у вопрошающего все в порядке, так как компилятор или код, реально трактует the value 204 as( а не instead of, как чел с вопросом) false.
Еще раз, в строках дебага MS VS2019 две переменные выглядят так
equ_x true bool
equ_y true (204) bool
в блок < int a = 0; . ;>
В коде
[b]if(equ_x && equ_y)< int a = 0;
. ;>[/b]
не попадает.
Но это явно не ашибка алгоритма, а какой-то сдой то ли компилятора, то ли сам не знаю чего.
Так как сравниваемые переменные rct_fr[fr_i].qx rct_fl[fl_i].qx и rct_fr[fr_i].qy rct_fl[fl_i].qy
в
bool equ_x = equal(rct_fr[fr_i].qx, rct_fl[fl_i].qx);
bool equ_y = equal(rct_fr[fr_i].qy, rct_fl[fl_i].qy);
равны согласно тому же дебагеру, более того, они даже не BigInteger. A просто 1/5 и 1/6;
Re: true(204) в C++ что за зверь?
10.11.2022, 17:16
| Заслуженный участник |
Покажите более содержательный кусок кода, и без bb тегов. Что такое true(204) — непонятно, это не скомпилируется.
bool в дебагере может показываться как угодно, стандарт ничего про битовое представление true не требует.
(при всей моей нелюбви к MSVS, я довольно сильно уверен, что ошибка в коде, а не в компиляторе)
Re: true(204) в C++ что за зверь?
10.11.2022, 17:33
Последний раз редактировалось Sender 10.11.2022, 17:41, всего редактировалось 1 раз.
Явно неинициализированная переменная. Любое ненулевое число при приведении его к булеву типу даст true, но я не уверен, что может получиться, когда оно участвует в булевой операции. Может, там через побитовые операции над числами всё реализовано. В таком гипотетическом случае побитовое «и» чисел
и
(стандартное значение, соответствующее true) даст, разумеется,
$» />. Постарайтесь всё же разобраться, откуда там у вас это
взялось, выведите, например, отдельно значения

для этого случая.
Можно ещё добавить, что aka
Re: true(204) в C++ что за зверь?
10.11.2022, 17:36
| Заслуженный участник |
Sender в сообщении #1569639 писал(а):
но я не уверен, что может получиться, когда оно участвует в булевой операции
Если там неинциализированная переменная — то что угодно. Например компилятор проверит, что в эту переменную никто точно не мог записать false , и значит ветки, предполагающие, что там false , можно выкинуть. А потом аналогично с true .
Re: true(204) в C++ что за зверь?
10.11.2022, 17:48
bool equ_x = equal(rct_fr[fr_i].qx, rct_fl[fl_i].qx);
bool equ_y = equal(rct_fr[fr_i].qy, rct_fl[fl_i].qy);
Но это, конечно, не выход.
Re: true(204) в C++ что за зверь?
10.11.2022, 18:00
Последний раз редактировалось TheRuinedMap 10.11.2022, 18:16, всего редактировалось 2 раз(а).
MGM в сообщении #1569636 писал(а):
По сути у вопрошающего все в порядке, так как компилятор или код, реально трактует the value 204 as( а не instead of, как чел с вопросом) false.
Это прекрасно. Почему компилятор так «трактует» такое 204 — я детально объяснил выше. Никаких проблем или вопросов о «трактовке» 204 не существует. Здесь все ясно и компилятор тут совершенно прав.
MGM в сообщении #1569636 писал(а):
Но это явно не ашибка алгоритма, а какой-то сдой то ли компилятора, то ли сам не знаю чего.
Никакого сбоя компилятора в «трактовке» 204 нет. Вопрос тут только в том, откуда взялось это 204 в переменной типа bool . Такого быть не должно.
MGM в сообщении #1569636 писал(а):
Так как сравниваемые переменные rct_fr[fr_i].qx rct_fl[fl_i].qx и rct_fr[fr_i].qy rct_fl[fl_i].qy
в
bool equ_x = equal(rct_fr[fr_i].qx, rct_fl[fl_i].qx);
bool equ_y = equal(rct_fr[fr_i].qy, rct_fl[fl_i].qy);
равны согласно тому же дебагеру, более того, они даже не BigInteger. A просто 1/5 и 1/6;
Вот это все, скорее всего, совершенно не имеет никакого отношения к делу. Я глубоко сомневаюсь, что значение 204 было порождено вашей функцией equal . Ваша переменная получила свое 204 не отсюда. Либо вы что-то напутали и смотрите на совсем другую переменную (неинициализированную), либо переменная сначала получила нормальное значение, но потом была затерта «мусором» 204 позже, вследствие каких-то посторонних причин.
Не видя остального кода, трудно судить о том, что и где там у вас произошло. У упомянутого вами вопрошающего на «анголоязычном форуме» произошло что-то аналогичное, ибо, как я сказал выше, затирание значения байтом 0xCC — распространенное явление при разнообразных выходах за пределы массива, неаккуратной работе с динамической памятью и т.п.
Приводите более полный код, желательно воспроизводящий проблему. Есть некий шанс, что дело именно в equal , но тогда это должно быть видно из сгенерированного ассемблерного кода.
True c что это
Есть способ получить переменную bool не равную ни true, ни false. При этом разные компиляторы работают по-разному. В Microsoft 2005 в следующем фрагменте кода можно сравнивать переменную b c true или false, и мы зайдем в else (если мне не изменяет память). В gcc (точно в последних версиях) уже необходимо сравнивать с функцией bool g(), чтобы зайти в else.
Есть два вопроса:
1. Какое поведение должно быть по стандарту, может ли переменная типа bool быть не равна ни true, ни false?
2. Какое поведение в других компиляторах/версиях?
#include int f() < return 4; >bool g() < return true; >int main() < //bool b = reinterpret_cast(f)(); bool b = ((bool (*)())f)(); if (b == g()) // b == true < printf("true"); >else if (b == !g()) // b == false < printf("false"); >else < printf("bool is not equal to true or false"); >return 0; >
P.S. Аналогичная ситуация с языком C и типом _Bool, не равным ни 1, ни 0.
Re: C++/C bool != true и false
| От: | watchmaker | |
| Дата: | 26.06.14 19:12 | |
| Оценка: | 11 (2) +1 | |
Здравствуйте, Jukier, Вы писали:
J>Есть два вопроса:
J>1. Какое поведение должно быть по стандарту,
По стандарту тут UB:
A function pointer can be explicitly converted to a function pointer of a different type. The effect of calling
a function through a pointer to a function type (8.3.5) that is not the same as the type used in the definition
of the function is undefined.
Я понимаю, что сама задача определить как компилятор представляет тип bool на низком уровне может быть занятной. Но ты делаешь это неправильно, а твой код ломается раньше.
J> может ли переменная типа bool быть не равна ни true, ни false?
В правильной программе на С++ — не может.
J>2. Какое поведение в других компиляторах/версиях?
Re: C++/C bool != true и false
| От: | _niko_ |
| Дата: | 26.06.14 19:12 |
| Оценка: |
Здравствуйте, Jukier, Вы писали:
J>может ли переменная типа bool быть не равна ни true, ни false?
Конечно, ведь ты же сам «сказал» компилятору (reinterpret_cast) что то что записано в int это не int вовсе а bool, он же согласно букве закона стандарта тебе не перечит — верит на слово.
J>Какое поведение должно быть по стандарту
В общем случае UB.
На деле если тот тип что на месте int‘а «влазит» в тот тип что на месте bool‘а — может и обойдется
Re[2]: C++/C bool != true и false
| От: | Jukier |
| Дата: | 27.06.14 04:21 |
| Оценка: |
Здравствуйте, watchmaker, Вы писали:
W>Здравствуйте, Jukier, Вы писали:
J>>Есть два вопроса:
J>>1. Какое поведение должно быть по стандарту,
W>По стандарту тут UB:
A function pointer can be explicitly converted to a function pointer of a different type. The effect of calling
W>a function through a pointer to a function type (8.3.5) that is not the same as the type used in the definition
W>of the function is undefined.
Спасибо за указание места, где это определено.
W>Я понимаю, что сама задача определить как компилятор представляет тип bool на низком уровне может быть занятной. Но ты делаешь это неправильно, а твой код ломается раньше.
В Microsoft VS 2005 bool занимает 1 байт: true == 1, false == 0. А в этом примере b == 4 (и там, как я помню, для захода в else функция g() не была нужна). Меня удивило, что в gcc (g++) есть разница между сравнением с true и false напрямую и через функцию.
J>>2. Какое поведение в других компиляторах/версиях?
W>Всё то же UB.
Если есть под рукой последняя Microsoft Visual Studio (или более поздняя, чем 2005), то буду благодарен, если посмотрите, как работает там приведенный кусок кода с явным сравнением с true и false.
Re[2]: C++/C bool != true и false
| От: | Jukier |
| Дата: | 27.06.14 04:28 |
| Оценка: |
Здравствуйте, _niko_, Вы писали:
__>Здравствуйте, Jukier, Вы писали:
J>>может ли переменная типа bool быть не равна ни true, ни false?
__>Конечно, ведь ты же сам «сказал» компилятору (reinterpret_cast) что то что записано в int это не int вовсе а bool, он же согласно букве закона стандарта тебе не перечит — верит на слово.
Этот момент я понял, но в стандарте есть про приведение других типов к bool, где сказано, что все ненулевое — это true.
J>>Какое поведение должно быть по стандарту
__>В общем случае UB.
__>На деле если тот тип что на месте int‘а «влазит» в тот тип что на месте bool‘а — может и обойдется
Спасибо за ответ, но если «влазит», то тоже не обойдется, проверено (см. ответ на пред. пост).
Re[3]: C++/C bool != true и false
| От: | _niko_ |
| Дата: | 27.06.14 06:07 |
| Оценка: |
Здравствуйте, Jukier, Вы писали:
J>. в стандарте есть про приведение других типов к bool, где сказано, что все ненулевое — это true.
это про static_cast(. ) — если с ним скомпилилось значит привидение типа пойдет по стандарту.
reinterpret_cast никакое привидение не поддерживает — как я уже писал тут компилятор перестает брыкаться и делает как велино.
Re[3]: C++/C bool != true и false
| От: | watchmaker | |
| Дата: | 01.07.14 16:29 | |
| Оценка: | 25 (2) | |
Здравствуйте, Jukier, Вы писали:
J> Меня удивило, что в gcc (g++) есть разница между сравнением с true и false напрямую и через функцию.
Я боюсь, что у тебя уже появляются не совсем верные ассоциации между представлением bool и «сравнением напрямую и через функцию». То есть связь там действительно может быть (об этом ниже), но формально в твоём примере до этого не доходит. У тебя там UB при вызове функций (а не при сравнении bool) — и на этом можно заканчивать разговор, код может делать что угодно и это уже не обязательно связано с самим bool. Вот, например, один из компиляторов решает что будет выводить ещё до запуска программы: http://goo.gl/Hr9xWL — то есть там сравнений вообще не делается, а вся программа просто вырождается в единственный вызов печати. Чем это вырождение объясняется? Твой экспериментальный код не даёт ответа.
J>В Microsoft VS 2005 bool занимает 1 байт: true == 1, false == 0. А в этом примере b == 4 (и там, как я помню, для захода в else функция g() не была нужна).
Короче, тут всё не так просто. То что в памяти bool занимает один байт (и имеет два разрешенных значения 0 и 1) совсем не означает, что в регистре он будет представлен таким же образом, и тем более это не означает, что при передачи в другие процедуры (написанные в том числе на других языках) будет сохраняться то же соглашение. В общем случае не верно, что во всех трёх вышеописанных ситуациях bool на низком уровне хранится и трактуется одинаковым образом.
И чтобы в этом всём не запутаться придумали документацию — ABI. И лучше документацию читать
Вот, например, популярная платформа system V amd64 abi. Если открыть этот документ, то можно прочитать, что в памяти bool всегда занимает 1 байт и всегда равен 0 (ложь) или 1 (истина). Но тот же bool в регистре ведёт себя по другому — истиной считается уже не только 1, но и вообще любые ненулевые значения. При вызове же процедур значение bool хранится в младшем бите, при этом остальные биты младшего байта нулевые, а остальные биты — не определены.
Смог бы ты без документации своими экспериментами эти правила вывести? Вряд-ли. Да и бессмысленное это занятие. Прочитать — и проще, и надёжнее.
Начинать нужно с учебников и справочников, а не бросаться сразу писать глючный код и пытаться его объяснить.
Впрочем, после прочтения документации можно уже и проверять полученные знания
# nasm -f elf64 -o fn.o fn.asm global foo, bar, baz foo: mov rax, 18364758544493064704 ret bar: mov rax, 18437098717332255489 ret baz: mov rax, 3 ret
Так согласно ABI функция foo возвращает значение false, функция bar — значение true, а функция baz — запрещённое значение.
То есть любой компилятор C/C++ на упомянутой платформе будет корректно (и полностью определённо) работать с результатом вызова foo или bar, но поведение при вызове baz неопределено.
Небольшая проверка:
#include extern "C" bool foo(); extern "C" bool bar(); extern "C" bool baz(); void test(const char* name, bool (*fn)()) < printf("%s:\n", name); const char* str[2] = "\tfalse", "\ttrue">; switch(fn()) < case false: puts("\tfalse"); break; case true: puts("\ttrue"); break; default: puts("\t?"); break; > puts(str[fn()]); > int main() < #define TEST(fn) test(#fn, fn) TEST(foo); TEST(bar); TEST(baz); >
И вот такие возможные выводы наблюдаются при разных компиляторах и разных их настройках:
foo: false false bar: true true baz: ?
foo: false false bar: true true baz: false 1�H��1�I��^H��H���PTI���@
foo: false false bar: true true baz: true Segmentation fault (core dumped)
Видно, что с baz вечно происходит что-то странное. А вот foo и bar вполне работают однозначно (и будут работать так всегда на этой платформе с любым компилятором).
Re[4]: C++/C bool != true и false
| От: | Jukier |
| Дата: | 03.07.14 18:08 |
| Оценка: |
Здравствуйте, watchmaker, Вы писали:
W>Короче, тут всё не так просто.
Благодарен за столь полный ответ, с огромным удовольствием прочитал (все бы так отвечали).
W>Я боюсь, что у тебя уже появляются не совсем верные ассоциации между представлением bool и «сравнением напрямую и через функцию». То есть связь там действительно может быть (об этом ниже), но формально в твоём примере до этого не доходит. У тебя там UB при вызове функций (а не при сравнении bool) — и на этом можно заканчивать разговор, код может делать что угодно и это уже не обязательно связано с самим bool.
У меня вопросы возникают: как в каком компиляторе сделано и почему. То что UB, а дальше можно форматировать диск, меня не удовлетворяет . Ну дальше сам почитаю, ещё раз спасибо.