Перейти к содержимому

True c что это

  • автор:

Когда переменная 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, но я не уверен, что может получиться, когда оно участвует в булевой операции. Может, там через побитовые операции над числами всё реализовано. В таком гипотетическом случае побитовое «и» чисел $204$и '$(стандартное значение, соответствующее true) даст, разумеется, <img decoding=$» />. Постарайтесь всё же разобраться, откуда там у вас это $204$взялось, выведите, например, отдельно значения

$204$

для этого случая.
Можно ещё добавить, что 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, а дальше можно форматировать диск, меня не удовлетворяет . Ну дальше сам почитаю, ещё раз спасибо.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *