10 ms·
Linus: bool is dangerous in C if you don't understand it
- clay 13y agoThis documentation for stdbool.h says exactly what he says is wrong: http://pubs.opengroup.org/onlinepubs/007904875/basedefs/stdbool.h.html http://pubs.opengroup.org/onlinepubs/007904875/basedefs/stdb... It's interesting though... does anyone know of specific cases of the problems he's refering to?
- yuubi 13y agoC99 6.3.1.2 requires that converting nonzero to _Bool yields a 1. An int doesn't work that way.
- revelation 13y agobool a = value & (1 << 5) a will be 1 or 0, not 1 << 5. You don't get this behavior with a normal int. MSVC also has a warning about some of this behavior [1], with a nonsense performance subtext. I don't think theres a GCC equivalent. 1: http://msdn.microsoft.com/en-us/library/b6801kcy.aspx http://msdn.microsoft.com/en-us/library/b6801kcy.aspx
- deleted 13y ago[deleted]
- skybrian 13y agoSeems like the only reason you'd expect it to be 1 << 5 is that you've been working with a broken definition of bool using #define. In any sane language you can't redefine bool that way, nobody would ever expect bool to take more than two values, and there wouldn't be a problem.
- kansface 13y agoBut, this is the case in every other language I can think of. IE, bools have one of two possible states; as a human 1<<5 is neither true nor false.
- mbell 13y agoConsider a simple bit mask operation, assume 8 bit ints for the sake of brevity: Prior to C99, assuming you use the mentioned typedef for bool: bool a = someInt & 0x02 'a' will be 0x02 if the bit is set. In C99, bool is aliased to _Bool and if the flag is set, the above code will result in 'a' being 0x01 because of C99's requirements for type conversion. To accurately get the same behavior prior to C99, you can add !!, e.g.: bool a = !!(someInt & 0x02) //'a' is now 0x01 when the bit is set.
- Silhouette 13y agoMost, if not all, of the problems people are describing in this discussion come down to trying to assign something that isn't a boolean value to a variable of boolean type, and expecting it to do something sensible. I don't see how this is ever going to have a happy ending. If you had written bool a = (someInt & 0x02) == 0x02 or something similarly clear and unambiguous, nothing odd would happen, even in C. (Edit: OK, that's not strictly true, because of the operator precedence order. It's never made sense to me that integer arithmetic operators have higher precedence than comparisons but bitwise logical operators have lower precedence, so if you remove the parentheses above then the resulting code doesn't do what you'd expect. I suppose this is because I'm looking at the problem as if comparison operators return a proper boolean value rather than an integer, and the ordering we've wound up with in C dates from a historical oddity about 40 years ago.) The underlying problem with booleans in C99, as Linus and others have been saying, is that the language doesn't actually enforce basic type safety, so cases like your first example bool a = someInt & 0x02 that should result in a type error are allowed through, and with odd results: how does it make any sense for a boolean variable to have an integer value like 0x01 or 0x02? Then programmers who relied on such odd results wind up writing horrific code like your second example bool a = !!(someInt & 0x02) where fudge factors build on top of distortions to make the old hacks work. And then we wonder why in 2013 we still have widely used, essential software that is riddled with security flaws and crash bugs. :-(
- caf 13y agoThe reason that & and | have lower precedence than the comparison operators is indeed historical - it's because the earliest versions of the language didn't have the logical boolean operators && and ||, so the bitwise & and | operators stood in for them. The lower precedence meant that you could write: if (x == 1 & y == 2) { ..and have it do what you meant. This became a bit of a wart when the && and || operators were introduced (still well before ANSI standardisation), but it was considered that changing it would have broken too much existing code.
- asveikau 13y agoYou missed the part where _Bool is not the same as int.
- norswap 13y agoNote that he also denounces the implicit conversion rules.
- chatman 13y agoThe biggest upside is better readability of code, esp. when you're glancing over documentation of functions.
- tonetheman 13y agoI read the article and in fact the versions of stdbool look pretty close to what he said. Maybe there is some subtly there I am missing but I do not see it.
- induscreep 13y agoThe subtlety is that bool expands to _Bool, not int. So bool is actually a macro, not "typedef int bool" as in Linus' example code snippet.
- yuubi 13y agoThe important bit seems to be the behavior of the _Bool type, not the macroness (also, the [Future Directions section of the Open Group spec](http://pubs.opengroup.org/onlinepubs/007904875/basedefs/stdbool.h.html#tag_13_46_06 http://pubs.opengroup.org/onlinepubs/007904875/basedefs/stdb...) says #undefing and redefining the macros is obsolescent, leaving open the possibility of changing the implementation from a macro to something else entirely).
- gnud 13y agoLinus' example code was showing a typical compatability hack, that can easily cause unintended consequenses and hard-to-debug problems.
- ridiculous_fish 13y agoHere's the advantage of C99's bool. Lots of C projects do something like this: typedef char bool; and then maybe they use it like so: bool found_it = strstr(haystack, needle); This has a serious bug that will only manifest 0.4% of the time. The problem is that strstr returns a pointer, and converting a pointer to a smaller integer type throws away the high bytes. If the resulting pointer is not NULL but happens to have a zero low byte, this bool will be false, even though the string was found. Even if that doesn't happen, you'll often see code like this: #define true 1 ... if (found_it == true) ... which is wrong as well. bool addresses these. Conversions to bool always result in values of 0 or 1, so both of the above problems are avoided. That said, I agree with Linus. It's not well understood, and using bool in a library header may conflict with another definition of bool in the project. Also, compilers typically warn about at least the first error above. As a C99 feature, bool is too little, too late; had it been part of C89, things might be different.
- chmike 13y agoThat needed to be clarified and was missing in Linus reply. It is a very important point, from the language perspective.
- MaxGabriel 13y agoThis pointer-to-bool bug isn't theoretical, either—it happened to me just a few months ago. The Cocoa function NSAssert works on objects, and raises an exception on a nil pointer. A similar assertion in a library I was using was simply casting to BOOL (a signed char), causing the error you described. It was a nightmare to debug, since it was interacting with a black box that I believed was the source of the problem.
- ajross 13y ago"warning: initialization makes integer from pointer without a cast" I mean sure, there are warnings and there are warnings. Absurdist pedantry about warning states isn't something I tend to worry about. But if you're dealing with a code base that is building to completion without attention to this warning (which pops out with the default flags on gcc 4.7.2 -- no -Wall needed!), then you have more serious problems than can be fixed by a builtin pointer-to-bool conversion.
- losethos 13y agoMy bool is a char. I'm not going to add junk to my compiler for actual bool support. I guess I could explain that. I have a ToBool(StrStr()) function.
- altrego99 13y agoUsing bool in C, as well as C++ has distinct advantages. If Linus or some idiot cannot control himself from making mistakes, and from causing serious damage to the code, it is his fault. You can always aim it at your foot given any construction tool. I don't care if fools can't control it, but I wouldn't say no to bool.
- dchichkov 13y agoJust for a reference, how many decades of C experience are behind your comment? Nothing personal here, it is just one really need that information to put your reply into context.
- lucisferre 13y agoWhy?
- dchichkov 13y agoWell,... wanted to give OP a chance to put his/her comment into context. It is just some times, on HN, you really don't know what kind of experience is standing behind the comment.
- girvo 13y agoThis is the only forum I've ever been on where I can be presently surprised by how much experience actually is behind a statement. Its a nice change for once.
- fredsanford 13y agoSounds like someone with limited experience with OPC... (Other Peoples Code) Ever worked on a big code base where some programmers were in Vietnam, some in Russia, some in China and most here in the US? Conventions are different and pride and communications issues make it hard to correct behavior. Ever worked as the commit point for an offshore group? Code review? Didn't think so...
- 13y ago
- kineticfocus 13y agoI recall a recent post that looks at other definitions of the boolean ... http://nshipster.com/bool/ http://nshipster.com/bool/ We need to develop one universal standard... :)
- pivnicek 13y agoNever understood why we needed a boolean type, myself. What is wrong with 1 and 0?
- fredsanford 13y agoWhat's wrong with anything that's not false is true? If you treat it this way you remove the vast majority of the problems with most C or C++ BOOL implementations. The low bytes of a pointer being 0 (It can happen on Windows with VirtualAlloc and company) can screw up the works, so avoid assigning a pointer to a BOOL and use BOOL b = !!pointer if you have to break that rule.
- chrismcb 13y agoWhy not make the correct comparison and do BOOL b = pointer != NULL. Now the code says what you mean, is easy to understand, and assigns a boolean value to a bool.
- to3m 13y ago!!p does the same as p!=NULL. The choice is purely stylistic. (!p is equivalent to p==NULL; !!p is therefore equivalent to !(p==NULL). Or, alternatively, p!=NULL.)
- tel 13y agoBecause the properties of other types might not translate. It's probably okay with integer types since (a + b) => (a OR b) and (a * b) => (a AND b) as long as you stay away from upper bounds. But some semantic maps are less great. Having your compiler help you to ensure you're not implicitly mixing up bad maps can be helpful.
- mullr 13y agoBecause in a statically typed language, you want the type of a symbol to represent the set of values it can be bound to. We often have the set {something that passes a truth test, something that fails a truth test} in our programs, so a boolean type is a nice way to represent it. Now, this is not the same thing defining what exactly the truth test is. It's perfectly reasonable and arguably a good design to have both a narrow boolean type and a wide definition of truthiness.
- innguest 13y agoC: the language that can't even get a boolean type right. And that stuff was standardized by a committee? Wow.
- gizmo686 13y agoWhy should C get boolean write. As a language, it is very close to the hardware, and the hardware doesn't actually have the concept of a bit. The smallest unit that modern processors expose is a byte, so it makes sense that the smallest datatype C has is also a byte.
- innguest 13y agoNo need to define boolean in terms of a bit just because that's all it takes. There's no harm in being redundant and using a whole byte for it, so that -1 is true and 0 is false.
- noselasd 13y agoHardware certainly has the concept of a bit, otherwise it couldn't have bit operations, it doesn't have a data type that's a bit though, but it neither has structs or in some cases long longs or pointers. bool helps statically analyzers better as well.
- coldtea 13y ago>C: the language that can't even get a boolean type right. And that powers 99% of the software that matters. Name me one language that you cannot say similar BS about some aspect of it.
- nknighthb 13y agoBrainfuck!
- gaius 13y agoThere are 2 kinds of languages, my friend. Those people complain about, and those no one uses.
- dscrd 13y agoI wonder if Linus has ever tried better languages.
- aa0 13y agoRuby on Rails and your single-origin latte is calling. C is the most performant for years now, a large part of the kernel is in assembly. Remember to download your gems tonight, rude boy.
- dima55 13y agoAre you proposing the kernel be rewritten in a "better" language?
- enneff 13y agoI have no idea how you derived that from that comment.
- coldtea 13y agoHe derived by you saying "better". For what he does there is NO better language than C. So what would be a "better language"? Haskell? In what way would it be better -- since it wouldn't be better for the tasks he wants? Abstract better? Sorry, I don't believe in that.
- aa0 13y agoYou forget you're on HN where slow ass designer languages are all the hail. Sigh..
- dmit 13y agoIs C the best possible choice for Git? For Subsurface? For the embroidery template converter thingie he wrote for his wife? Linus used C for all of those, but was it because C was technically the best choice in each case, or because it was good enough to get the job done and because it's the language he's most comfortable with?
- cLeEOGPw 13y agoEven after reading all the comments I am not sure should I use bool in C code or not. I am C++ programmer only starting to have some fun in C. Linus says: If "bool" had real advantages (like having a dense array representation, for example). But doesn't bool have the advantage of reducing perceived complexity of the code and making the code more understandable? If the function returns int, one might assume it is some number, and he would have to use documentation or look at code samples to find out the int is only being compared to 1 or 0. Type bool instantly tells there's some kind of check or flag that is returned, and makes it undoubtedly easier to tell what's going on. As for casting rules other mentioned, doesn't the C compiler warn about anything converting to anything that can store less information than what it converts from?
- pavlov 13y agoNormally you get a warning when the destination type is smaller, but with C99 bool you don't because that's how the standard is written: any non-zero value of any other type is implicitly converted to "true". That's why C99 bool typecasting problems are so subtle. If you were previously using typedef char BOOL and you switch to the "real" bool, you don't get compiler warnings about suspicious casting anymore.
- andrewcooke 13y agobut you don't have the bug either, right? because it doesn't take only the first byte. so what's the problem? (genuine question - have never used _Bool and am trying to get a handle on this thread).
- pavlov 13y agoIndeed, the C99 bool fixes this particular bug, but it can introduce new bugs because its semantics are different from other C types. C99 bool allows you to assign a larger integer or a pointer to a bool with no warning. As illustrated by the grandparent commentor, the general assumption is that the C compiler will always warn you about these situations. If bool had been always been part of the standard, people would be aware of this issue. But it wasn't, and so the C world is full of BOOL typedefs that can be chars, ints or whatever, and it's easy for programmers to implicitly assume that the "real" bool behaves like the typedefs they're used to.
- ksk 13y agoX is dangerous in Y if you don't understand it. Indeed.
- TelmoMenezes 13y agoSandwiches are dangerous in astronomy if you don't understand it?
- jk4930 13y agoOf course. Imagine, during the assembly process, someone eats his sandwich while hanging over the mirror of some space telescope. Do you think the all those dots you're seeing on the NASA images are stars? And once they discover the peanut butter nebula, they have to update parts of the astronomy books.
- foxhill 13y agofor all y in Y, Y is the subset of all computer programming languages, y is dangerous if you do not understand Y.
- kingkilr 13y agoReally though, what isn't dangerous in C if you don't understand it. (Hell, most of C is dangerous even if you understand it).
- timothya 13y agoI think the point he is trying to make is that most people think they understand it when they really don't.
- snarfy 13y agoNobody ever said bool was a bit.
- eliasmacpherson 13y agoDon't think anyone has mentioned this: bool is also subject to integer promotion so when you pass a bool to a function or do some integer arithmetic it can become an int. From the text K&R, C Programming Language, 2nd Ed. p. 174 A.6.1 Integral Promotion A character, a short integer, or an integer bit-field, all either signed or not, or an object of enumeration type, may be used in an expression wherever an integer may be used. If an int can represent all the values of the original type, then the value is converted to int; otherwise the value is converted to unsigned int. This process is called integral promotion.
- michaelcampbell 13y ago> Linus: bool is dangerous in C if you don't understand it What in C is NOT dangerous if you don't understand it?
- pmelendez 13y agoWell... Everything is dangerous in any language if you don't understand it.
- derekp7 13y agoThat may be true. However something is more dangerous if it is very easy (or common) to mis-understand it. I think that is the point that Linus was trying to get at -- bool is dangerous because it is likely to be misunderstood.
- slackpad 13y agoC++ tried to use template specialization with std::vector<bool> to take advantage of bool-ness and provide a dense storage for bits, but it suffers for reasons Linus points out here, namely the inability to cleanly address individual elements of the vector (so it doesn't behave exactly like a normal std::vector).
- twoodfin 13y agoRight. At the time, as I understand it, the standards committee thought reference semantics and operator overloading would be powerful enough to create perfect "proxy" objects that would be indistinguishable from their direct equivalents. std::vector<bool> ended up demonstrating the opposite. std::bitset<N> is quite nice though, as long as you have a fixed size.
- adamgravitis 13y agoI think it's fair to say just about anything is dangerous in C if you don't understand it...
- StephenFalken 13y ago"variadic macros and bool are just adornment" in The future according to Dennis Ritchie (a 2000 interview) [1] [1] http://www.itworld.com/lw-12-ritchie?page=0,1 http://www.itworld.com/lw-12-ritchie?page=0,1