6 ms·
Here'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 =
by ridiculous_fish 13y ago
Here'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.
- ben0x539 13y agoArguably that warning just suggests that you put in a cast, which makes it no more correct. Then you get another warning "cast from pointer to integer of different size [-Wpointer-to-int-cast]" which apparently is also on by default, but I'm not sure it's immediately obvious to a casual C programmer how that will go wrong.
- ajross 13y agoAgain, I'd argue that if you have a programmer willing to throw in a double cast expression (!) to work around a warning without once thinking about what they are trying to do (in this case to check if a pointer is NULL) then you have problems that aren't going to be well addressed by a C99 bool anyway. I mean, this example is a little contrived as it is. The "normal" way to treat a pointer as a boolean and branch off of it is just "if(ptr)", and that's worked without trouble on all compilers for 40 years now. Is C sort of a mess? Yeah. But this isn't a particularly illustrative example IMHO. All languages have this nonsense (c.f. the Ruby/JS "Wat" video).
- EpicEng 13y agoNo it doesn't. Not to anyone who knows C anyway.
- mtdewcmu 13y agoCasting pointers to integers isn't all that common to do. When I see that warning, I take it very seriously, because it almost always means I made a real mistake.
- nknighthb 13y agoIt's gotten better the last few years, but I still see that exact warning all the time in open-source projects. Nobody cares about warnings until someone mandates -Werror.
- crest 13y agoCFLAGS+=-Wall -Wextra -pedantic -Werror # have fun
- cmccabe 13y agoIn the example you gave, any compiler from the last 10 years would have given a warning message when converting the pointer to an int. Ignoring error messages is extremely, extremely bad practice. If you are still doing that, I suggest auditing your code right now to see if there are more problems such as mismatched printf arguments and so forth. bool is a bad thing in C and C++, because of the implicit conversion rules. In C++, pointers implicitly convert to bool in every context-- there is never any warning message. This effectively reduces the compiler's ability to typecheck your program, since so many variables are pointers already, and C++ will happily stuff them into any bool argument to a function. It seems like the C99 _Bool type implements the same implicit type conversion brain damage. That makes it a step backwards in terms of type safety, not forwards. That's right, using the old-fashioned, fuddy-duddy, plain old int and 0 and 1 gives you better type checking than the shiny new C++ feature. As Linux points out, the worse typechecking comes with a side order of compatibility problems. And it is not any more efficient or readable.
- rwg 13y agoIt seems like the C99 _Bool type implements the same implicit type conversion brain damage. It does: "When any scalar value is converted to _Bool, the result is 0 if the value compares equal to 0; otherwise, the result is 1." (from §6.3.1.2 of the N1256 draft) Compilers will happily compare/set pointers to 0 since that's the null pointer constant (§6.5.9, §6.3.2.3), so there's no warning: % cat foo.c #include <stdio.h> int main() { _Bool b = "blah"; printf("%d\n", b); return 0; } % gcc -std=c99 -W -Wall -Wextra -o foo foo.c % ./foo 1
- comex 13y agoHave you ever actually encountered a bug involving accidentally passing a pointer to a 'bool' function argument? I've seen many obscure kinds of bugs, but don't remember ever in my life seeing one of those- so I suspect this is a red herring. (And of course if the value passed happens to be an int rather than a pointer, typedefing bool to int won't save you!) edit: And as mentioned in the rest of the thread, while it's unjustifiably confusing to, say, pass 'p' as a boolean parameter rather than 'p != NULL', it's not unreasonable to do something like typedef int bool; bool foo_enabled; void set_foo_enabled(bool enabled) { if(enabled == foo_enabled) return; /* new value is different, do some work */ } set_foo_enabled(1); ... set_foo_enabled(flags & ENABLE_FOO); Though I haven't come across this kind of bug in practice either.
- kumarharsh 13y ago>> As a C99 feature, bool is too little, too late; had it been part of C89, things might be different. I'm failing to understand this line. Can you be more explicit why it's bad now, and would have been good earlier?
- Kliment 13y agoBecause lots of compilers in common use, particularly from Microsoft, don't support C99 so to work around their assheadedness you have to put in compatibility workarounds. Those workarounds behave differently from compiler-implemented bool, and the risk of errors from those inconsistencies is significantly greater than the benefit of using bool in code.
- stephencanon 13y ago"Lots of" compilers in common use? Can you name one besides Microsoft's?
- tzs 13y agoAnother problem with that typedef and usage is that it assumes that NULL as an integer is 0. It need not be. The literal constant 0 cast to or assigned to a pointer type always works because they compiler treats that as a special case, and replaces the 0 with whatever the actual NULL bit pattern for that pointer type. E.g., "char * p = 0" might actually generate something like "move #0xFFFFFFFF, p" on a machine where 0xFFFFFFFF is the bit pattern for NULL char pointers. A lot of people forget this, and think that NULL pointers must actually have a bit pattern that is all zeros.
- joosters 13y agoName me a common system where NULL != 0 You might as well be worrying about code compatibility with systems that have a 7 bit char, or some other irrelevance.
- MaulingMonkey 13y agoC++ member pointers are frequently represented as offsets into the class on vanilla x86. Given that 0 is an entirely valid offset -- the first member given a class without initial padding or vtable -- NULL must of course be represented by an entirely different, nonzero, bitpattern.
- icedchai 13y agohmm? you're adding an offset to a pointer (the base of the object), which is still not going to equal 0 even if the offset is 0.
- MaulingMonkey 13y agoThe C++ standard calls pointers to members... well, pointers to members. I'm not offsetting anything: The compiler is on my behalf. It could create function stubs for all I care, similar to how one might emulate this feature in C#. #include <iostream> struct Foo { int bar; }; int main() { int (Foo::*null_pointer) = nullptr; int (Foo::*first_member_pointer) = &Foo::bar; std::cout << *(std::ptrdiff_t*)&null_pointer << "\n"; std::cout << *(std::ptrdiff_t*)&first_member_pointer << "\n"; } Running this code after compiling it with VS2012 results in, on my machine: -1 0
- johnchristopher 13y agoAs a really bad C programmer I have a question, if you don't mind my asking: Is that the kind of knowledge/insight you gain from understanding C when studying it or when you are bitten by a bug ?
- marcosdumay 13y agoYou get that kind of insight by reading the specification. If you are anything like me, you'll only actually read it when you are bitten by a bug. But that's not universal, there are people that like to know the ins and outs of the language before using it... and yes, they are the ones doing the right thing.
- shin_lao 13y agoProbably better: bool found_it = !!strstr(haystack, needle);
- mtdewcmu 13y agoLinus is usually dead-on in language matters. bool as a type in C strikes me as dubious. In C, you need to care about the underlying representation of things. I'm not even sure it was a good idea to call a char a char, because it's actually a small integer. Calling it a char is just misleading; it's signed, and a literal character is not even a char. It's a source of bugs. "bool" sounds potentially worse.