LINUX.ORG.RU

тип bool в C


0

0

Не могу понять, что происходит с типом bool. пустая прога:

int main() { bool bval; return 0; }

при компиляции 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'???

Прикинь, и в самом деле нет.

anonymous
()

Типа bool в С действительно нет. Точнее, в версиях стандарта до C99 его действительно нет. В С99 он есть, но называется _Bool. Кроме того, определен заголовочный файл <stdbool.h> в котором определен `bool' как синоним для _Bool. Сделано это было, чтобы не нарушать совместимость с существующим кодом. GCC поддерживает С99 в этом отношении. Однако особого смысла в использовании _Bool/bool я не вижу, т.к. в плане проверки типов это обычный целочисленный тип (совместимый по присваиванию с int и так далее). Единственная особенность -- явное приведение к _Bool дает всегда либо 0 либо 1 (это, однако, не означает, что переменная типа _Bool будет занимать в памяти один бит) -- точно такой же эффект может быть достигнут при помощи `!!'

aa5779
()

А не проще писать так?
#define TRUE 1
#define FALSE 0

Ну и для полной радости
typedef unsigned short bool;

OxiD ★★★★
()
Ответ на: комментарий от OxiD

short занимает 2 байта, может быть вместо него использовать char?

CyberCoder
() автор топика

Компилятор при сравнениях и прочих операциях будет приводить char к int, так что ты выиграешь (может быть) в памяти, но проиграешь (какие-то копейки) в скорости.

Конструкция
typedef enum {false, true} bool;

будет лучше (IMHO), чем #define.

nobody ★★
()

Oxid ты уверен что 0 - это false?

мне кажется что должно быть что то типа

#define TRUE (1 == 1)
#define FALSE (!TRUE)

typedef enum {false, true} bool; может не прокатить в конструкции

while (!false) {
  /* XXX */
}

т.к. enum не обязан начинаться с 0 да и я не уверен что 0 это на
самом деле false

lg ★★
()

Ну здрасьте, всегда в условиях проверяли числа и указатели на 0 просто if(!number) а тут оказывается false!=0... приехали.

AL

anonymous
()

> enum не обязан начинаться с 0
Согласно стандарту языка Си, первый элемент перечисления по умолчанию равен 0.

> я не уверен что 0 это на самом деле false
Если использовать конструкцию
enum {false, true};
то слово 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 ★★
()

Плохо не то что false == 0, а то что true == 1; Значит проверки на x == true будут проваливаться для большинства случаев.

В C нет булевского типа - лучше с этим смириться и вести себя соответсвенно, а не смущать народ.

anonymous
()

> Значит проверки на x == true будут проваливаться
> для большинства случаев

bool fn() {return true;}

int main()
{
if (fn() != true) puts("anonymous прав");
return 0;
}

Если функция возвращает либо false, либо true, все будет работать.
Если функция возвращает char *, то fn() == true работать не будет.
Но то же самое верно и для Си++.
При чем здесь "В C нет булевского типа - лучше с этим смириться и вести себя соответсвенно, а не смущать народ"?

nobody ★★
()

> Если функция возвращает char *, то fn() == true работать не будет.

Именно. Догадайтесь почему. (Правильный ответ - нет встроенного преобразования char* -> bool, т.к."В C нет булевского типа" )

> Но то же самое верно и для Си++.

При чем здесь это? Кстати и в С++ bool не слишком нужен. (Я не имею в виду vector<bool>).

> При чем здесь "В C нет булевского типа - лучше с этим смириться и вести себя соответсвенно, а не смущать народ"?

Проверки типа '!= NULL', '== FALSE', '== TRUE' в С не только бесполезны, но и вредны. Тот кто их применяет - напрашивается на неприятности сам и делает код менее читаемым для окружающих.

anonymous
()

2nobody

К тому же вы передергиваете. Сравните 

bool fn() {return true;}

int main()
{
    if (fn() != true) puts("anonymous прав");
    return 0;
} 

и 

bool fn() { return 45; }

main()
{
    if(fn() == true)
        puts("nobody стопудово прав");
    return 0;
}

(typedef enum {false, true} bool; подразумевается)

anonymous (*) (2003-03-02 21:37:36.281)

anonymous
()

false == 0
frue == не 0 (любое число != 0)

anonymous
()

Предпоследнему 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) нарушаешь общепринятые правила: объявляешь функцию так, будто она возвращает значение перечислимого типа, а на самом деле она возвращает другое.
Вот поясняющий пример:


typedef enum {one, two, three} e;

e fn() {return 1000000000;}

int main()
{
static const char c[] = "123";
putchar(c[fn()]);
puts("segfault почему-то не случился");
return 0;
}

nobody ★★
()

> Похоже, имеет место непонимание друг друга. 

Да похоже.

> Пример. 
>
> /* При успешном выполнении функция возвращает 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
()
Ответ на: комментарий от nobody

> Для каждой подобной функции.
> Если такая функция одна, то не стоит и огород городить.
> А если их два десятка, то программа (IMHO) будет читаться легче -- 
> потому что достаточно взглянуть на объявление функции в файле .h, 
> чтобы понять, что она возвращает. 

IMHO нет. Возвращаемые значения как раз и должны указываться в комментария в header'е.

> Если же функция объявлена как возвращающая int, то придется лезть в 
> файл .c, чтобы почитать комментарий -- ведь функция, возвращающая 
> int, может вернуть не только признак успешного/ошибочного 
> выполнения, но и вообще все, что угодно -- например, дескриптор 
> открытого файла. 

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

> Функция же, возвращающая bool, может вернуть только признак 
> успешности своего выполнения -- во всяком случае, так 
> подразумевается читающим программу.

Разумно.

> А ты в своем примере (с fn() == 45) нарушаешь общепринятые правила: 
> объявляешь функцию так, будто она возвращает значение перечислимого 
> типа, а на самом деле она возвращает другое.

Странно, а компилятор мне на это не указал :( Может быть правила не
такие уж общепринятые?

> Вот поясняющий пример:
>
> typedef enum {one, two, three} e;
>
> e fn() {return 1000000000;}
> 
> int main()
> {
> static const char c[] = "123";
> putchar(c[fn()]);
> puts("segfault почему-то не случился");
> return 0;
> }

Segmentation fault. В Си нет диапазонных типов.

anonymous
()

минимальное битовое представление энумов четко регламентируется в стандарте. И использование вида

enum EEE { a = 1; b = 2; c = 4; };

EEE e = (EEE)(a | c);

абсолютно законно (хотя и может коробить кого-то)

dilmah ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.