Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: bool "третье состояние"
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Cредства разработки для МК > IAR
HEX
Код
#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 ) мусор остается?
Так и должно быть?
AHTOXA
Вероятно, компилятор производит преобразования типа при присвоении bool = не_bool. А при присвоении bool=другой_bool он считает, что всё уже преобразовано до того, и не проверяет. Вы же, своим хитрым хаком
Код
   unsigned char* Ptr;
   Ptr = (unsigned char*)(&B);
   *Ptr = 13;                   //B = 13


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


В каждом компиляторе работа с bool может быть организована по-разному. Ваш компилятор очевидно конверсию в bool производит на этапе присваивания, а работает с bool-переменными, используя только их младший бит. Такой подход эффекитивен при компиляции, т.к. упрощает булевские операции, позволяя делать их "не глядя". В противном случае приведение типа пришлось бы делать при каждой булевской операции с ее использованием.
Таким образом "мусор" не мешает работе программы, поскольку все остальные биты, кроме младшего, в работе не участвуют.
AHTOXA
Цитата(HEX @ Jul 22 2009, 14:34) *
явное преобразование типа тоже не помогает:
Код
B2 = (bool)(B);              //B2 = 12


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

...

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


Явное преобразование типов указателей - это всегда очень опасная операция с возможно непредсказуемыми побочными эффектами. Ответственность за правильный результат лежит целиком на программисте, который должен понимать что делает. Компилятор же больше ни за что не отвечает. Если Вы не понимаете что хотите сделать и как будет результат интерпретирован - зачем пользуетесь такой опасной операцией? Взяли спички в руки, поигрались и удивляетесь, откуда пожар...
HEX
Цитата(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"
HEX
я в этом вижу потенциальную проблему, например, при чтении бинарного файла данных.Придется производить доп. операции, что бы избавиться от мусора:
Код
  //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;
Xenia
Цитата(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;
Сергей Борщ
Цитата(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 ну никак попасть не сможет.
Oldring
Цитата(HEX @ Jul 22 2009, 14:28) *
я в этом вижу потенциальную проблему, например, при чтении бинарного файла данных.


А кто сказал что можно недостаточно четко специфицированное бинарное представление с одного компа на другой переносить? Попробуйте перенести даже обычные целые числа с little-endian на big-endian машины. Не говоря уже про указатели wink.gif Такова уж жизнь - про внешнее представление нужно думать особо, чтобы не получать неожиданности.
tag
Цитата(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 предполагает использование преопределенных констант для данной реализации компилятора.
HEX
Цитата(Сергей Борщ @ 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 ) по моему, должно работать четко.
Oldring
Цитата(HEX @ Jul 22 2009, 18:57) *
А явное преобразование B = (bool)( B ) по моему, должно работать четко.


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

}


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

или что-то типа того. Не во всех компиляторах bool - встроенный тип. А был бы встроенным, не надо было никакого файла дополнительно инклюдировать.
ReAl
Цитата(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;
должно бы работать правильно, но не лучше ли обойтись без извращений?
KRS
Цитата(Xenia @ Jul 22 2009, 15:00) *
Это потому, что поверка одного бита "стоит" ровно столько же, сколько проверка всех битов - тестирование регистра на нулевое значение занимает столько же инструкций, как и тестирование одного его бита.

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

К тому же очень полезно смотреть листинги, на максимальной оптимизации! И будет видно как компилер работает с булевыми переменными.
Сергей Борщ
Цитата(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).
sensor_ua
Использование выражений типа
Код
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).
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.