I keep wishing that there was a Valgrind-like tool that could detect and report undefined behavior. It would have to be a dynamic, runtime tool, since many/most cases of undefined behavior cannot robustly detected statically. But it would need to have more information at runtime about the original C program than Valgrind has; the assembly alone does not contain enough information to know if the source C program is invoking undefined behavior.
I feel certain that if this tool existed, we would find scores of undefined behavior in all but the most conscientious C programs.
Afaik, GCC has some flags for specific types of undefined behavior.
- sign up for the developers' list at http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev ,
- skim over http://clang.llvm.org/hacking.html ,
- build from 'trunk' by carefully following a few simple steps in http://clang.llvm.org/get_started.html ,
- wade in and reproduce your bug ,
... and then share your findings.
Together we can build better tools. Anyone with patience and interest can help.
The only point I wanted to make was that a collective effort might help cut down on ambiguity in expression that the compiler does not identify. I think we could use "more warnings".
Dont code C if you dont know what you are doing.
Also, I'm willing to bet that that if you've written any significant amount of C, you have some undefined behavior that you're not aware of. Just because it works doesn't mean it's defined behavior according to the standard.
Logically, you're doing two things. You're negating the bool and then you're testing that negated value. This is what's expressed in the code generated from the non-optimized version. In the optimized version, the compiler has optimized this into a single jne instruction. I can understand why they wouldn't want to do it for non-optimized builds.
It sounds like gcc always uses xor for negating bools. If all you're doing is negating a bool, it's just a single instruction that involves no branching. It could be the fastest way.
I wonder what the fastest way to negate (boolean-wise) a value other than a bool would be. Maybe you just do a test and then set the value based on a xor of the zero flag.
Probably "NOT reg". Exists in most CPU architectures, and is generally smaller (in variable-size instruction sets) than "XOR reg, immed".
Another trick is to use the carry flag, i.e., NEG reg; MOV reg, 0; ADC reg, 0. This works for all 386-compatible processors and is reasonably fast.
If you need to find a use for it, it might make it easier to spot an undefined behaviour later and finding its cause ("hey, this evalutates both to true and false, it must be an unitialized bool!").
So it's still interesting and might not be completely pointless.
Still, I'm glad you're interested in the language, if you're interested in undefined behaviour then you should carefully and closely read the latest free draft standard (N1570) and perhaps implement a small C compiler of your own ( Appel : Modern Compiler Implementation ).
There are many C compilers, they are free to do whatever they want when behaviour is undefined and in many cases you'll unfortunately not see anything odd at all, not until you port your code, change your flags or upgrade the compiler and then you'll having a seething mass of "well this stuff worked when we tested it" errors.
Strapping yourself into a vehicle and driving off a cliff teaches you a little about the dangers of accidents and gives you a reason to drive safely, it doesn't particularly teach much about the practice of safe driving.
The example code drove off the road, what happened next really isn't all that exciting.
Wikipedia, Boolean in C:
if, while, for, etc., treat any non-zero value as true
The if test is correct. It's using non-zero as "truth". That's what you're talking about, and there's absolutely no question that it's doing the right thing here.
The negation is not using non-zero for truth, because it's a negation of a bool, and bools are restricted to only being 0 and 1. However since this particular bool is undefined, the in-memory representation happens to not meet that restriction. But that doesn't matter. The value is undefined. The negation could, quite legally, cause demons to fly out your nose. The fact that you've observed, prior to the negation, that the value appears to be true has no meaning. Undefined values remain undefined even after observation and after manipulation.
Compiler writers. C exists mostly to be a portable language that's easy to compile. A better question is why would you write programs in C in 2012.
>No language implementer WOULD do that to an int.
It certainly happened to float/double on some older architectures where the internal representation included different flag bits. I wouldn't be at all surprised if it happened to char and short. I guess there's an argument for using int for all variables in your program (since memory isn't usually constrained enough nowadays for it to be worth using short etc.), but again, if you weren't memory-constrained why would you be using C?
>My development group avoids bool like the plague, using int instead - it has well-defined size, behavior and sensible warnings
Int might not suffer from this particular behaviour, but if you use an uninitialized variable it will bite you sooner or later. The article's takeaway isn't "avoid bool", it's "initialize your variables"
"When any scalar value is converted to _Bool, the result is 0 if the value compares equal to 0; otherwise, the result is 1"
http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf page 43
It makes me wonder if that's actually undefined behaviour in C++, because unlike the example in the fine article this time the behaviour of the program does not depend on the (undefined) value of b. Or maybe it's just g++ being clever.
How come the voltage on an unknown wire is just allowed to change like that - what are the laws of physics for!