реклама на сайте
подробности

 
 
> bool "третье состояние"
HEX
сообщение Jul 22 2009, 07:34
Сообщение #1


Участник
*

Группа: Свой
Сообщений: 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 ) мусор остается?
Так и должно быть?
Go to the top of the page
 
+Quote Post
2 страниц V   1 2 >  
Start new topic
Ответов (1 - 18)
AHTOXA
сообщение Jul 22 2009, 07:47
Сообщение #2


фанат дивана
******

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



Вероятно, компилятор производит преобразования типа при присвоении bool = не_bool. А при присвоении bool=другой_bool он считает, что всё уже преобразовано до того, и не проверяет. Вы же, своим хитрым хаком
Код
   unsigned char* Ptr;
   Ptr = (unsigned char*)(&B);
   *Ptr = 13;                   //B = 13


избежали проверки при присвоении значения переменной типа bool, и перехитрили компилятор.


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
HEX
сообщение Jul 22 2009, 08:34
Сообщение #3


Участник
*

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



явное преобразование типа тоже не помогает:
Код
B2 = (bool)(B);              //B2 = 12
Go to the top of the page
 
+Quote Post
Xenia
сообщение Jul 22 2009, 08:38
Сообщение #4


Гуру
******

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



Цитата(HEX @ Jul 22 2009, 10:34) *
Почему при присваивание непосредственно числа все нормально ( B = 13 ), а при присваивании другово bool ( B2 = B ) мусор остается? Так и должно быть?


В каждом компиляторе работа с bool может быть организована по-разному. Ваш компилятор очевидно конверсию в bool производит на этапе присваивания, а работает с bool-переменными, используя только их младший бит. Такой подход эффекитивен при компиляции, т.к. упрощает булевские операции, позволяя делать их "не глядя". В противном случае приведение типа пришлось бы делать при каждой булевской операции с ее использованием.
Таким образом "мусор" не мешает работе программы, поскольку все остальные биты, кроме младшего, в работе не участвуют.
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Jul 22 2009, 08:40
Сообщение #5


фанат дивана
******

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



Цитата(HEX @ Jul 22 2009, 14:34) *
явное преобразование типа тоже не помогает:
Код
B2 = (bool)(B);              //B2 = 12


B2 = (int)( B ) ; ?


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
Oldring
сообщение Jul 22 2009, 08:47
Сообщение #6


Гуру
******

Группа: Свой
Сообщений: 3 041
Регистрация: 10-01-05
Из: Москва
Пользователь №: 1 874



Цитата(HEX @ Jul 22 2009, 11:34) *
Ptr = (unsigned char*)(&B);
*Ptr = 13; //B = 13

...

Так и должно быть?


Явное преобразование типов указателей - это всегда очень опасная операция с возможно непредсказуемыми побочными эффектами. Ответственность за правильный результат лежит целиком на программисте, который должен понимать что делает. Компилятор же больше ни за что не отвечает. Если Вы не понимаете что хотите сделать и как будет результат интерпретирован - зачем пользуетесь такой опасной операцией? Взяли спички в руки, поигрались и удивляетесь, откуда пожар...


--------------------
Пишите в личку.
Go to the top of the page
 
+Quote Post
HEX
сообщение Jul 22 2009, 08:56
Сообщение #7


Участник
*

Группа: Свой
Сообщений: 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"
Go to the top of the page
 
+Quote Post
HEX
сообщение Jul 22 2009, 10:28
Сообщение #8


Участник
*

Группа: Свой
Сообщений: 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;
Go to the top of the page
 
+Quote Post
Xenia
сообщение Jul 22 2009, 11:00
Сообщение #9


Гуру
******

Группа: Модератор 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;
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Jul 22 2009, 11:11
Сообщение #10


Гуру
******

Группа: Модераторы
Сообщений: 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)
Go to the top of the page
 
+Quote Post
Oldring
сообщение Jul 22 2009, 11:17
Сообщение #11


Гуру
******

Группа: Свой
Сообщений: 3 041
Регистрация: 10-01-05
Из: Москва
Пользователь №: 1 874



Цитата(HEX @ Jul 22 2009, 14:28) *
я в этом вижу потенциальную проблему, например, при чтении бинарного файла данных.


А кто сказал что можно недостаточно четко специфицированное бинарное представление с одного компа на другой переносить? Попробуйте перенести даже обычные целые числа с little-endian на big-endian машины. Не говоря уже про указатели wink.gif Такова уж жизнь - про внешнее представление нужно думать особо, чтобы не получать неожиданности.


--------------------
Пишите в личку.
Go to the top of the page
 
+Quote Post
tag
сообщение Jul 22 2009, 12:13
Сообщение #12


Частый гость
**

Группа: Свой
Сообщений: 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 предполагает использование преопределенных констант для данной реализации компилятора.
Go to the top of the page
 
+Quote Post
HEX
сообщение Jul 22 2009, 14:57
Сообщение #13


Участник
*

Группа: Свой
Сообщений: 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 ) по моему, должно работать четко.
Go to the top of the page
 
+Quote Post
Oldring
сообщение Jul 22 2009, 15:34
Сообщение #14


Гуру
******

Группа: Свой
Сообщений: 3 041
Регистрация: 10-01-05
Из: Москва
Пользователь №: 1 874



Цитата(HEX @ Jul 22 2009, 18:57) *
А явное преобразование B = (bool)( B ) по моему, должно работать четко.


B = (bool)(int)( B )


--------------------
Пишите в личку.
Go to the top of the page
 
+Quote Post
sergeeff
сообщение Jul 22 2009, 17:15
Сообщение #15


Профессионал
*****

Группа: Свой
Сообщений: 1 481
Регистрация: 10-04-05
Пользователь №: 4 007



Цитата(HEX @ Jul 22 2009, 11:34) *
Код
#include <stdbool.h>

}


Судя по тому, что вы подключаете в проект файл stdbool.h - тип bool не встроен в компилятор, а реализован через некоторое переопределение, типа
#define bool int

или что-то типа того. Не во всех компиляторах bool - встроенный тип. А был бы встроенным, не надо было никакого файла дополнительно инклюдировать.
Go to the top of the page
 
+Quote Post
ReAl
сообщение Jul 22 2009, 19:52
Сообщение #16


Нечётный пользователь.
******

Группа: Свой
Сообщений: 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;
должно бы работать правильно, но не лучше ли обойтись без извращений?


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post
KRS
сообщение Jul 22 2009, 21:02
Сообщение #17


Профессионал
*****

Группа: Модераторы
Сообщений: 1 951
Регистрация: 27-08-04
Из: Санкт-Петербург
Пользователь №: 555



Цитата(Xenia @ Jul 22 2009, 15:00) *
Это потому, что поверка одного бита "стоит" ровно столько же, сколько проверка всех битов - тестирование регистра на нулевое значение занимает столько же инструкций, как и тестирование одного его бита.

Это для очень многих процессоров не правда! Во многих случаях проверка на нулевое значение быстрее(инструкция меньше места занимает) или вообще не требует инструкции!

К тому же очень полезно смотреть листинги, на максимальной оптимизации! И будет видно как компилер работает с булевыми переменными.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Jul 22 2009, 23:27
Сообщение #18


Гуру
******

Группа: Модераторы
Сообщений: 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)
Go to the top of the page
 
+Quote Post
sensor_ua
сообщение Jul 23 2009, 08:28
Сообщение #19


Профессионал
*****

Группа: Свой
Сообщений: 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 просто никогда не работает (ну и не очень-то и хотелосьwink.gif).


--------------------
aka Vit
Go to the top of the page
 
+Quote Post

2 страниц V   1 2 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 6th July 2025 - 01:04
Рейтинг@Mail.ru


Страница сгенерированна за 0.01584 секунд с 7
ELECTRONIX ©2004-2016