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

 
 
> 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 - 14)
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

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

 


RSS Текстовая версия Сейчас: 3rd July 2025 - 10:55
Рейтинг@Mail.ru


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