C nie ma żadnych wbudowanych typów boolowskich. Jaki jest najlepszy sposób na użycie ich w C?
C nie ma żadnych wbudowanych typów boolowskich. Jaki jest najlepszy sposób na użycie ich w C?
Odpowiedzi:
Od najlepszych do gorszych:
Opcja 1 (C99)
#include <stdbool.h>
Opcja 2
typedef enum { false, true } bool;
Opcja 3
typedef int bool;
enum { false, true };
Opcja 4
typedef int bool;
#define true 1
#define false 0
Jeśli nie jesteś zdecydowany, idź z numerem 1!
<stdbool.h> boolwybranego kompilatora mogą być bardziej odpowiednie do zamierzonego celu wartości boolowskiej niż wykorzystanie int(tzn. kompilator może wybrać implementację boolinną niż an int). Jeśli masz szczęście, może to również skutkować bardziej rygorystycznym sprawdzaniem typu w czasie kompilacji.
intz bool? To marnotrawstwo. Zastosowanie unsigned char. Lub użyj polecenie wbudowane c za _Bool.
Kilka przemyśleń na temat booleanów w C:
Jestem wystarczająco stary, że używam zwykłego ints jako mojego typu logicznego bez żadnych typedefs, specjalnych definicji lub wyliczeń dla wartości prawda / fałsz. Jeśli zastosujesz się do mojej poniższej sugestii, aby nigdy nie porównywać stałych stałych boolowskich, wystarczy użyć 0/1, aby zainicjować flagi. Takie podejście można jednak uznać za zbyt reakcyjne w dzisiejszych czasach. W takim przypadku należy zdecydowanie skorzystać, <stdbool.h>ponieważ przynajmniej ma tę zaletę, że jest znormalizowana.
Jakiekolwiek są stałe logiczne, używaj ich tylko do inicjalizacji. Nigdy nie pisz czegoś takiego
if (ready == TRUE) ...
while (empty == FALSE) ...
Zawsze można je zastąpić jaśniejszym
if (ready) ...
while (!empty) ...
Pamiętaj, że można je właściwie odczytać na głos.
Nadaj swoim zmiennym logicznym pozytywne nazwy, tj full Zamiast notfull. Ten ostatni prowadzi do kodu, który jest trudny do odczytania. Porównać
if (full) ...
if (!full) ...
z
if (!notfull) ...
if (notfull) ...
Obie poprzednie pary czytają naturalnie, chociaż !notfulltrudno jest je czytać w obecnej postaci, i stają się znacznie gorsze w bardziej złożonych wyrażeniach boolowskich.
Ogólnie należy unikać argumentów logicznych. Rozważ funkcję zdefiniowaną w ten sposób
void foo(bool option) { ... }
W treści funkcji jest bardzo jasne, co oznacza argument, ponieważ ma wygodną i, miejmy nadzieję, znaczącą nazwę. Ale wyglądają strony z połączeniami
foo(TRUE);
foo(FALSE):
W tym przypadku zasadniczo nie można powiedzieć, co oznacza parametr, nie zawsze patrząc na definicję lub deklarację funkcji, a staje się znacznie gorzej, gdy dodasz jeszcze więcej parametrów boolowskich. Sugeruję albo
typedef enum { OPT_ON, OPT_OFF } foo_option;
void foo(foo_option option);
lub
#define OPT_ON true
#define OPT_OFF false
void foo(bool option) { ... }
W obu przypadkach wygląda teraz strona połączeń
foo(OPT_ON);
foo(OPT_OFF);
który czytelnik ma przynajmniej szansę na zrozumienie bez pogłębiania definicji foo.
a == bdziała?
ai blicząc od zera, poleciłbym a > 0 == b > 0zamiast tego. Jeśli nalegasz na wykorzystanie prawdziwości arbitralnych niezerowych wartości, otrzymasz !!varwartość logiczną 0/1 równą var, więc możesz napisać !!a == !!b, chociaż wielu czytelników uzna to za mylące.
!a == !bjest również wystarczający do testowania równości, niezerowe stają się zerami, a zera stają się jednością.
!!ajako „przekonwertować wartość niebędącą boolowską na jej równoważną wartość prawdy”, podczas gdy przeczytałbym !ajako „logicznie odwróć zmienną boolowską a”. W szczególności szukałem konkretnego powodu, dla którego logiczna inwersja była pożądana.
Wartość logiczna w C jest liczbą całkowitą: zero dla wartości false i niezerowa dla wartości true.
Zobacz także typ danych logicznych , sekcja C, C ++, Objective-C, AWK .
Oto wersja, której użyłem:
typedef enum { false = 0, true = !false } bool;
Ponieważ fałsz ma tylko jedną wartość, ale logiczna prawda może mieć wiele wartości, ale technika ustawia true na to, co kompilator użyje w przeciwieństwie do fałszu.
To rozwiązuje problem z kodowaniem czegoś, co sprowadzałoby się do tego:
if (true == !false)
Myślę, że wszyscy zgodzilibyśmy się, że nie jest to dobra praktyka, ale jednorazowy koszt wykonania „prawda =! Fałsz” eliminujemy ten problem.
[EDYCJA] W końcu użyłem:
typedef enum { myfalse = 0, mytrue = !myfalse } mybool;
aby uniknąć kolizji nazw z innymi schematami, które definiowały trueifalse . Ale koncepcja pozostaje taka sama.
[EDYCJA] Aby wyświetlić konwersję liczby całkowitej na wartość logiczną:
mybool somebool;
int someint = 5;
somebool = !!someint;
Pierwszy (najbardziej odpowiedni)! konwertuje niezerową liczbę całkowitą na 0, a następnie drugą (najbardziej w lewo)! konwertuje 0 na amyfalse wartość. Zostawię to jako ćwiczenie dla czytelnika do konwersji zerowej liczby całkowitej.
[EDYCJA] Moim stylem jest używanie jawnego ustawienia wartości w wyliczeniu, gdy wymagana jest konkretna wartość, nawet jeśli wartość domyślna byłaby taka sama. Przykład: Ponieważ fałsz musi wynosić zero, używam false = 0,raczej niżfalse,
true, falsei boolsą podświetlone w większości IDE, ponieważ są wartości enum i typedef, w przeciwieństwie do #defines, które są rzadko składnia podświetlona.
gcc -ansi -pedantic -Wallnie daje ostrzeżeń, więc ufam gcc; Jeśli to c89zadziała, to i tak powinno działać na dobre c99.
!może tylko zwracać wartości 0i 1dlatego true = !falsezawsze przypisuje wartość 1. Ta metoda nie zapewnia żadnego dodatkowego bezpieczeństwa typedef enum { false, true } bool;.
if(!value)), ale wyjątek ten nie ma zastosowania w tym konkretnym przypadku.
Jeśli używasz kompilatora C99, ma on wbudowaną obsługę typów bool:
#include <stdbool.h>
int main()
{
bool b = false;
b = true;
}
Najpierw pierwsze. C, tj. ISO / IEC 9899 ma typ boolowski od 19 lat . To o wiele dłużej niż oczekiwana długość kariery programistycznej w C z amatorskimi / akademickimi / zawodowymi częściami połączonymi podczas odwiedzania tego pytania . Mój przewyższa to o zaledwie może 1-2 lata. Oznacza to, że w czasie , gdy przeciętny czytelnik w ogóle nauczył się czegoś o C, C faktycznie miał logiczny typ danych .
Dla typu danych, #include <stdbool.h>i wykorzystania true, falsea bool. Lub nie dołączaj go i używaj _Bool, 1a 0zamiast tego.
Istnieją różne niebezpieczne praktyki promowane w innych odpowiedziach na ten wątek. Zajmę się nimi:
typedef int bool;
#define true 1
#define false 0
Jest to nie-nie, ponieważ przypadkowy czytelnik - który nauczył się C w ciągu tych 19 lat - spodziewałby się, że boolodnosi się do faktycznego bool typu danych i zachowałby się podobnie, ale tak nie jest! Na przykład
double a = ...;
bool b = a;
W przypadku C99 bool/ _Bool, bwartość false iff byłaby arówna zero, a truepoza tym. C11 6.3.1.2p1
- Kiedy dowolna wartość skalarna jest konwertowana
_Bool, wynikiem jest 0, jeśli wartość jest równa 0; w przeciwnym razie wynik to 1. 59)Przypisy
59) NaN nie porównują równe 0, a zatem przeliczają na 1.
Z typedefna miejscu, doublebyłby zmuszony do int- jeżeli wartość podwójnej nie mieści się w zakresie do intThe zachowanie jest niezdefiniowane .
Oczywiście to samo dotyczy, jeśli truei falsezostały zadeklarowane w enum.
Jeszcze bardziej niebezpieczne jest deklarowanie
typedef enum bool {
false, true
} bool;
ponieważ teraz wszystkie wartości oprócz 1 i 0 są nieprawidłowe i gdyby taka wartość została przypisana do zmiennej tego typu, zachowanie byłoby całkowicie niezdefiniowane .
Dlatego jeśli nie możesz użyć C99 z jakiegoś niewytłumaczalnego powodu, dla zmiennych boolowskich powinieneś użyć:
inti wartości 0i 1 jak jest ; i ostrożnie wykonuj konwersje domen z innych wartości na te z podwójną negacją!!BOOL, TRUEi FALSE!intlub unsigned intdo przechowywania wyliczenia, ale nie znam nic w standardzie, co spowodowałoby, że wyliczenie działałoby jak coś innego niż liczba całkowita rodzaj.
typedef enum {
false = 0,
true
} t_bool;
!0 = 1według normy C i !a = 0dla dowolnej niezerowej wartości a. Problem polega na tym, że wszelkie niezerowe są uważane za prawdziwe. Więc jeśli ai boba są „prawdziwe”, niekoniecznie jest tak, że `a == b`.
C ma typ boolowski: bool (przynajmniej przez ostatnie 10 (!) Lat)
Dołącz stdbool.h, a true / false będzie działać zgodnie z oczekiwaniami.
boolmakra, które rozwija się do _Bool. Różnica jest ważna, ponieważ możesz #undefmakra (i jest to dozwolone, przynajmniej jako środek przejściowy), ale nie możesz wpisać untypedefczcionki. Nie zmienia to jednak głównej myśli pierwszego komentarza.
Wszystkie niezerowe wartości są sprawdzane jako prawdziwe w operacjach boolowskich, więc możesz po prostu
#define TRUE 1
#define FALSE 0
i użyj stałych.
Tylko uzupełnienie innych odpowiedzi i wyjaśnienie, jeśli możesz używać C99.
+-------+----------------+-------------------------+--------------------+
| Name | Characteristic | Dependence in stdbool.h | Value |
+-------+----------------+-------------------------+--------------------+
| _Bool | Native type | Don't need header | |
+-------+----------------+-------------------------+--------------------+
| bool | Macro | Yes | Translate to _Bool |
+-------+----------------+-------------------------+--------------------+
| true | Macro | Yes | Translate to 1 |
+-------+----------------+-------------------------+--------------------+
| false | Macro | Yes | Translate to 0 |
+-------+----------------+-------------------------+--------------------+
Niektóre z moich preferencji:
_Boolczy bool? Oba są w porządku, ale boolwyglądają lepiej niż słowo kluczowe_Bool .booli _Boolsą: falselub true. Przypisywanie 0lub 1zamiast falselub truejest poprawne, ale trudniej jest je odczytać i zrozumieć przepływ logiki.Niektóre informacje ze standardu:
_BoolNIE jest unsigned int, ale należy do grup całkowitych bez znaku . Jest wystarczająco duży, aby pomieścić wartości 0lub1 .bool trueifalse pewno nie jest to dobry pomysł. Ta zdolność jest uważana za przestarzałą i zostanie usunięta w przyszłości._Boollub bool, jeśli wartość skalarna jest równa 0lub 0będzie się z nią porównywać 0, w przeciwnym razie wynikiem jest 1: _Bool x = 9; 9jest konwertowany na 1po przypisaniu x._Boolma 1 bajt (8 bitów), zwykle programiści kuszą, aby spróbować użyć innych bitów, ale nie jest to zalecane, ponieważ jedyną gwarancją jest to, że tylko jeden bit służy do przechowywania danych, a nie jak typ, charktóry ma 8 dostępne bity.Możesz użyć do tego znaku char lub innego kontenera o małej liczbie.
Pseudo kod
#define TRUE 1
#define FALSE 0
char bValue = TRUE;
int), ponieważ na niektórych architekturach znaczny spadek wydajności wynika z konieczności rozpakowywania / maskowania tych zmiennych.
Możesz użyć _Bool, ale zwracana wartość musi być liczbą całkowitą (1 dla true, 0 dla false). Zaleca się jednak dołączenie i użycie bool jak w C ++, jak powiedziano w tej odpowiedzi z forum daniweb , a także w tej odpowiedzi , z tego innego pytania dotyczącego przepełnienia stosu :
_Bool: typ logiczny C99. Bezpośrednie korzystanie z _Bool jest zalecane tylko wtedy, gdy utrzymujesz starszy kod, który już definiuje makra dla bool, true lub false. W przeciwnym razie te makra są znormalizowane w nagłówku. Dołącz ten nagłówek, a będziesz mógł używać bool tak samo jak w C ++.
Wyrażenia warunkowe są uważane za prawdziwe, jeśli są niezerowe, ale standard C wymaga, aby operatory logiczne same zwracały 0 lub 1.
@Tom: #define TRUE! FALSE jest zły i całkowicie bezcelowy. Jeśli plik nagłówkowy trafia do skompilowanego kodu C ++, może to prowadzić do problemów:
void foo(bool flag);
...
int flag = TRUE;
foo(flag);
Niektóre kompilatory generują ostrzeżenie o konwersji int => bool. Czasami ludzie unikają tego, wykonując:
foo(flag == TRUE);
aby wymusić wyrażenie jako bool C ++. Ale jeśli zdefiniujesz PRAWDA! FAŁSZ, otrzymasz:
foo(flag == !0);
co kończy się porównywaniem wartości całkowitych, które i tak mogą wywołać ostrzeżenie.
Jeśli używasz C99, możesz użyć tego _Booltypu. Nie #includesą konieczne. Musisz jednak traktować to jak liczbę całkowitą, gdzie 1jest truei 0jest false.
Następnie możesz zdefiniować TRUEi FALSE.
_Bool this_is_a_Boolean_var = 1;
//or using it with true and false
#define TRUE 1
#define FALSE 0
_Bool var = TRUE;
#include <stdbool.h>i używasz bool, truei falsetak jak standard tego chce.
Możesz po prostu użyć #definedyrektywy w następujący sposób:
#define TRUE 1
#define FALSE 0
#define NOT(arg) (arg == TRUE)? FALSE : TRUE
typedef int bool;
I użyj w następujący sposób:
bool isVisible = FALSE;
bool isWorking = TRUE;
isVisible = NOT(isVisible);
i tak dalej
argi ekspresji jako całości #define NOT(arg) (((arg) == TRUE) ? FALSE : TRUE). Lepiej byłoby jednak sprawdzić pod kątem fałszu (da poprawną odpowiedź, nawet jeśli miałoby arg23 zamiast 0 lub 1: #define NOT(arg) (((arg) == FALSE) ? TRUE : FALSE)Ale całe wyrażenie można #define NOT(arg) (!(arg))oczywiście sprowadzić do , co daje ten sam wynik)