|
bool "третье состояние" |
|
|
|
Jul 22 2009, 07:34
|
Участник

Группа: Свой
Сообщений: 54
Регистрация: 25-11-04
Из: Тула
Пользователь №: 1 228

|
Код #include <stdbool.h>
int main() { bool B; B = 13; //B = 1 B = !B; //B = 0 unsigned char* Ptr; Ptr = (unsigned char*)(&B); *Ptr = 13; //B = 13 bool B2; B2 = B; //B2 = 12 B2 = !B; //B2 = 13 return 0; } Почему при присваивание непосредственно числа все нормально ( B = 13 ), а при присваивании другово bool ( B2 = B ) мусор остается? Так и должно быть?
|
|
|
|
2 страниц
1 2 >
|
 |
Ответов
(1 - 18)
|
Jul 22 2009, 08:34
|
Участник

Группа: Свой
Сообщений: 54
Регистрация: 25-11-04
Из: Тула
Пользователь №: 1 228

|
явное преобразование типа тоже не помогает: Код B2 = (bool)(B); //B2 = 12
|
|
|
|
|
Jul 22 2009, 08:38
|

Гуру
     
Группа: Модератор FTP
Сообщений: 4 479
Регистрация: 20-02-08
Из: Москва
Пользователь №: 35 237

|
Цитата(HEX @ Jul 22 2009, 10:34)  Почему при присваивание непосредственно числа все нормально ( B = 13 ), а при присваивании другово bool ( B2 = B ) мусор остается? Так и должно быть? В каждом компиляторе работа с bool может быть организована по-разному. Ваш компилятор очевидно конверсию в bool производит на этапе присваивания, а работает с bool-переменными, используя только их младший бит. Такой подход эффекитивен при компиляции, т.к. упрощает булевские операции, позволяя делать их "не глядя". В противном случае приведение типа пришлось бы делать при каждой булевской операции с ее использованием. Таким образом "мусор" не мешает работе программы, поскольку все остальные биты, кроме младшего, в работе не участвуют.
|
|
|
|
|
Jul 22 2009, 08:40
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(HEX @ Jul 22 2009, 14:34)  явное преобразование типа тоже не помогает: Код B2 = (bool)(B); //B2 = 12 B2 = (int)( B ) ; ?
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Jul 22 2009, 08:56
|
Участник

Группа: Свой
Сообщений: 54
Регистрация: 25-11-04
Из: Тула
Пользователь №: 1 228

|
Цитата(Xenia @ Jul 22 2009, 12:38)  Таким образом "мусор" не мешает работе программы... Если бы не мешали я бы может и не заметил: Код //B = 13 if (B == true) printf("true\n"); else printf("false\n");
B = !B; if (B == true) printf("true\n"); else printf("false\n"); выводит только "true"
|
|
|
|
|
Jul 22 2009, 10:28
|
Участник

Группа: Свой
Сообщений: 54
Регистрация: 25-11-04
Из: Тула
Пользователь №: 1 228

|
я в этом вижу потенциальную проблему, например, при чтении бинарного файла данных.Придется производить доп. операции, что бы избавиться от мусора: Код //data.bin = {0x0D, 0x00, 0x00, 0x00} f = fopen("data.bin", "r"); fread(&B, sizeof(B), 1, f); //B = 13 fclose(f); //Избавляемся от мусора if (B) B = true; else B = false;
|
|
|
|
|
Jul 22 2009, 11:00
|

Гуру
     
Группа: Модератор FTP
Сообщений: 4 479
Регистрация: 20-02-08
Из: Москва
Пользователь №: 35 237

|
Цитата(HEX @ Jul 22 2009, 11:56)  выводит только "true" Я уже объясняла, что сложности с набитыми мусором булевскими переменными возникают исключительно при проведении булевских операций над ними, что заставляет компилятор во имя эффективности использовать только младший бит этого числа. Однако при проверке булевой переменной (например для ветвления по оператору if) такой проблемы не возникает, и тут компилятор проверяет переменную "честно". Это потому, что поверка одного бита "стоит" ровно столько же, сколько проверка всех битов - тестирование регистра на нулевое значение занимает столько же инструкций, как и тестирование одного его бита. А вот булевские операции (типа ! ~ ^ & |) над одним битом производятся элементарно, а над мусорными переменными нет. Код //B = 13 if (B == true) printf("true\n"); else printf("false\n"); - тут B тестируется на ненулевое значение, а потому ЛЮБОЕ ненулевое значение B напечатает true. Код B = !B; if (B == true) printf("true\n"); else printf("false\n"); - а тут операция B = !B компилируется экономно - инверсией младшего бита. Можно было бы сразу инвертировать все биты числа, но мусор от этого останется мусором, но в false не превратится. Попробуйте сами вместо компилятора оттранслировать B = !B. Тогда поймете, что без ветвления по if/else этого сделать нельзя. Код //Избавляемся от мусора if (B) B = true; else B = false; Избавляться от мусора короче так: B = B ? true : false;
|
|
|
|
|
Jul 22 2009, 11:11
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(HEX @ Jul 22 2009, 13:28)  я в этом вижу потенциальную проблему, например, при чтении бинарного файла данных.Придется производить доп. операции, что бы избавиться от мусора: Естественно придется. Но несколько иначе: Код //data.bin = {0x0D, 0x00, 0x00, 0x00} f = fopen("data.bin", "r"); uint8_t Tmp; fread(&Tmp, sizeof(Tmp), 1, f); B = Tmp; fclose(f); Все. Компилятор знает, как преобразовать внутреннее представление uint8_t во внутреннее представление bool. Не надо мешать ему, пытаясь сделать его работу через неявное преобразование при помощи указателей. А если в вашем компиляторе bool будет 32 бита, что вы считаете из файла вашим методом? Цитата(HEX @ Jul 22 2009, 11:56)  Если бы не мешали я бы может и не заметил: Код //B = 13 if (B == true) printf("true\n"); else printf("false\n"); Еще раз: каким образом вы присвоили B значение 13? Оператором B = 13 вы не можете присвоить переменной типа bool значение, отличное от true и false. Если вы присвоили через указатель на другой тип - это жульничество, и компилятор ведет себя как считает нужным. Ибо запись B = 13 фактически означает B = bool(13), и 13 в B ну никак попасть не сможет.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Jul 22 2009, 12:13
|
Частый гость
 
Группа: Свой
Сообщений: 151
Регистрация: 21-02-06
Пользователь №: 14 561

|
Цитата(HEX @ Jul 22 2009, 11:56)  Если бы не мешали я бы может и не заметил: Код //B = 13 if (B == true) printf("true\n"); else printf("false\n");
B = !B; if (B == true) printf("true\n"); else printf("false\n"); выводит только "true" ...посмотрите в дизассемблере код который соответствует этому фрагменту Цитата(HEX @ Jul 22 2009, 10:34)  Код #include <stdbool.h>
int main() { bool B; B = 13; //B = 1 B = !B; //B = 0 unsigned char* Ptr; Ptr = (unsigned char*)(&B); *Ptr = 13; //B = 13 bool B2; B2 = B; //B2 = 12 B2 = !B; //B2 = 13 return 0; } Почему при присваивание непосредственно числа все нормально ( B = 13 ), а при присваивании другово bool ( B2 = B ) мусор остается? Так и должно быть? Так и должно быть, потому что тип bool предполагает использование преопределенных констант для данной реализации компилятора.
|
|
|
|
|
Jul 22 2009, 14:57
|
Участник

Группа: Свой
Сообщений: 54
Регистрация: 25-11-04
Из: Тула
Пользователь №: 1 228

|
Цитата(Сергей Борщ @ Jul 22 2009, 15:11)  А если в вашем компиляторе bool будет 32 бита у меня собственно так и есть, универсальность эта другая тема. Цитата(Сергей Борщ @ Jul 22 2009, 15:11)  Если вы присвоили через указатель на другой тип - это жульничество да жульничество, но интервейс вызова Read(void* Buff, int N) достаточно широко используется, есть и другие варианта попадание мусора в bool. Но проверять значение после подозрительных мест надо обязательно. Потом такой момент, если используется swtich, пусть даже с параметром enum, все равно в голове помним о левых значениях, которые обработаем default. При работе с bool переменными думается true/false, а там может и вигная какая то быть, причем "заразная", передается присваиванием ( B2 = B1 ). А явное преобразование B = (bool)( B ) по моему, должно работать четко.
|
|
|
|
|
Jul 22 2009, 19:52
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(sergeeff @ Jul 22 2009, 20:15)  Судя по тому, что вы подключаете в проект файл stdbool.h - тип bool не встроен в компилятор, а реализован через некоторое переопределение Если компилятор соответствует стандарту С99, то он должен иметь - встроенный тип _Bool с рангом ниже любого целочисленного типа, способный вместить 0 и 1, при приведении любого скалярного значения к _Bool оно приводится как (val == 0 ? 0 : 1)
- стандартный включаемый файл stdbool.h, который определяет
#define bool _Bool #define true 1 #define false 0
Так что если обсуждаемая ситуация касается С99-режима компиляции и bool не переопределён пользователем, то после Код bool b;
b = 13; в b будет корректное значение, ну а Код *(unsigned char *)&b = 13; как уже говорилось - неконтролируемая компилятором порнография, приводящая к UB. И при Код bool b, b1; *(unsigned char *)&b = 13; b1 = b; // и даже b1 = (bool)b; компилятор не обязан ничего проверять и "переприводить" - он не виноват, что в b левыми путями натолкали мусор. Частными случаями UB может быть и ожидаемое программистом поведение, и совершенно противоположное. Код b1 = (bool)(int)b; должно бы работать правильно, но не лучше ли обойтись без извращений?
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Jul 22 2009, 23:27
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(ReAl @ Jul 22 2009, 22:52)  Код b1 = (bool)(int)b; должно бы работать правильно Что-то меня сомнения гложат. Тогда уж и вылезать через ту же дырку,через которую влезли: Код b = (bool)(*(unsigned char *)&b); Цитата(HEX @ Jul 22 2009, 17:57)  да жульничество, но интервейс вызова Read(void* Buff, int N) достаточно широко используется, Угу. Для чтения тех же типов данных, которые были записаны при помощи Write(void* Buff,int N).
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Jul 23 2009, 08:28
|
Профессионал
    
Группа: Свой
Сообщений: 1 266
Регистрация: 22-04-05
Из: Киев
Пользователь №: 4 387

|
Использование выражений типа Код if(a == true) само по себе вроде и не страшно, но неправильно, потому как проверять по равенству/неравенству действительно можно только на false Цитата как Код (val == 0 ? 0 : 1) Цитата стандартный включаемый файл stdbool.h, который определяет #define bool _Bool #define true 1 #define false 0 Использую чуть другие буквы и не использую файл stdbool.h Код #define false 0 #define true (!(false)) Последняя строчка априори верна. true в таком случае опять же равно +1. Но, IMHO, использование в Си беззнаковых типов для bool и положительного значения для true это какая-то диверсия, что ли. Из знакового в беззнаковое преобразовать практически всегда возможно, а вот наоборот нет. Использую знаковое представление. Код typedef int bool; // для 8-и-битников typedef signed char bool Хотя это, если таки пытаться делать проверку на true, вылазит боком при использовании структур с битовыми полями объявленного знакового типа bool. Тогда компилятор при знаковом целом типе для bool считает значение поля не как 1, а как -1, а сравнение с true просто никогда не работает (ну и не очень-то и хотелось  ).
--------------------
aka Vit
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|