- Feature Articles
- CodeSOD
- Error'd
- Forums
-
Other Articles
- Random Article
- Other Series
- Alex's Soapbox
- Announcements
- Best of…
- Best of Email
- Best of the Sidebar
- Bring Your Own Code
- Coded Smorgasbord
- Mandatory Fun Day
- Off Topic
- Representative Line
- News Roundup
- Editor's Soapbox
- Software on the Rocks
- Souvenir Potpourri
- Sponsor Post
- Tales from the Interview
- The Daily WTF: Live
- Virtudyne
Admin
Hmm, well I'm not going to put money on it, but C11 defines
_Bool
to be big enough to contain 0 and 1 which suggests that, if the function returns a_Bool
there are, indeed, only two possible values for theswitch
.Admin
The critical safety system programmer should have had explicit handling of the FILE_NOT_FOUND. Or was it a homebrew boolean whose frist bool definition was true = !false?
Admin
TRWTF is to implement a safety critical system in anything other than a safety relay / safety PLC. You know, in a language / sub-system that only supports 16-bits integer arithmetic, and if you don't evaluate the overflow-bit immediately after performing an addition, your code won't even compile. (I'm looking at you, Siemens!)
Admin
C defines boolean values as FALSE = (int)0 and TRUE = !FALSE. It's important that it is not defined as TRUE = ~FALSE, because any other integer value than zero is considered TRUE.
And yes, I'm using uppercase on purpose, for a long time TRUE and FALSE where both just defined as marcos; C didn't had any keywords for true and false. Obviously this was not an issue, as long as you are aware of this fact and it also allowed for easy checks for return codes, which often returned 0 (so false) for OK.
Admin
"Capable of holding 0 or 1" does NOT mean incapable of holding other values, simply that such things are UB and flaming nasal demons are to be considered.
Admin
If we're being pedantic here: C11 (and C99 before it) only require
_Bool
to be at least large enough to hold 0 and 1. It can't be larger than unsigned char per the integer conversion ranks, so in practice it's exactly 1 byte.Per 6.3.1.2 Boolean type, values that are converted to
_Bool
get set to either 0 or 1, but it's possible to work around this with e.g.memcpy()
or similar operations that convert it to a character. And then even if you do that to write in any other value in the 2-255 range, when you convert back from_Bool
toint
, you still likely end up with 0 or 1 again depending on the compiler implementation (tested with Apple Clang 14.0.0). Only if you additionallymemcpy()
back out (or equivalent) can you confirm that yes, a_Bool
can in fact store larger values like 2-255.(But please don't ever do this in production code!)
Admin
re: "If we're being pedantic here"
Of course we are, why else are we here? ;-)
Admin
Yeah, you have to be really careful because in the part due to performance reasons some compilers used even int for bool in the past, because obviously it's way faster. 8-bit operations on modern architecture are most of the times slower than 32-bit or 64-bit operations, so for everything but storage it makes sense to use int over unsigned char. So beside of memcpy being a bad idea in the first place, you would also need to use sizeof() just to be sure and then hope that the compiler doesn't do magic expansion/compaction tricks. Ok, just lets say it's a bad bad idea :-)
Admin
please dont forget those lovely signed one bit integers
struct { int frist : 1; unsigned int skond : 1; } x;
x.frist has the value -1 and 0 .... x.skond has the value 0 and 1...
Just try reading these bitfields from a microcontroller and e.g. multiplying them by integer constants for a bit of a mind game.
Admin
The default case in this snippet is likely the result of a compiler warning.
gcc -Wall turns on a lot of warnings automatically, and is more or less standard for compiling commercially-developed code. One thing it turns on is -Wswitch, which will generate a warning for a switch/case statement if all the possible enumerations are not provided case blocks. Adding a default case prevents this warning.
What most likely happened here: the coder wrote the getBool() function to return either 0 (false) or true (1), with no other possible returns. The switch statement was coded assuming that - but there's no way to tell the compiler that it can only return 0 or 1. Compiler treats bool as an integer and complains because there are lots of un-cased enumeration values. So the coder added the emty default statement to prevent the warning.
The default case body should therefore be:
// shuts idiot compiler up
Admin
Old witches swiffer that emits familiar smell of ritten code.
Admin
I once inherited a Pascal app that had been ported from Basic.
The original Basic coder had actually tried to add some typing. Although the Basic only had the Integer and string types, he'd defined constants like int FALSE=0 and int TRUE=1, and any functions that started with "is" or "has" returned a boolean. So, "addition(x,y,z)" was an integer function that returned an integer, while "isValidInput(input)" or "hasAdminPriviledge(userId)" were both technically integer functions, but would only return integer values of FALSE(0) or TRUE(1).
Unfortunately, the Pascal coder clearly didn't understand booleans, or types in general, so he was flummoxed when he tried to port lines from the Basic code, such as "if (isValidInput(input) == TRUE)". It would generate a syntax fault, because isValidInput() was integer, and TRUE and FALSE were predefined as booleans in Pascal.
So, he did the only logical thing he could think of.
He defined integer values YES=1 and NO=0, so the code could be converted to "if (isValidInput(input) == YES)".
I fear to think what he might do with C, C++, or C# type languages.
Admin
No, it sould have been a simpler if(getBool()) do_something_else(); else do_something();
(Sorry for the too many elses, but I maintained the "names of the functions" ;-)
Admin
Well, if we're going for simplicity, the most simple approach in this context would be:
// yes, I like ternary operators. getBool() ? do_true_case_work() : do_everything_else_case_work();
But my point really was the reason for the presence of the default case. The reasoning I gave also applies for general enumerated types where there are more than two named values; the gcc -Wall option will still cause the compiler to complain if there's no default case. It's not actually possible to reach the default, assuming the getX() function can only return values defined within the enumerated type - but the compiler does not know that and complains about the missing default.