Introduction
If you’ve been programming in C or C++ for a while, you likely have heard of Duff’s Device that takes advantage of C’s often-derided “feature” where case blocks “fall through” into the next case (if any).
Regardless of what you think of that, I only recently discovered that there’s another “device” known as Clifford’s Device (alternatively known as Claire’s Device). While the problem it solves is completely different from Duff’s, it uses on another of C’s quirks.
Preamble
Sometimes you have a block of code that you want to delete temporarily, but don’t want to delete it permanently just in case you might need it again in the future.
If you’re using a VCS like git, of course you can delete the code because it’ll be preserved in the history, but, if you want the code back, you have to find the commit that deleted it and revert the commit. If the commit did more than simply delete the relevant code, then it gets harder.
As an alternative, you can use the preprocessor to disable a block of code:
#if 0
// ... disabled block of code ...
#endif
As another alternative, you can instead do:
if (0) {
// ... disabled block of code ...
}
Since 0 is always false, the code, though compiled, will never be executed. (The optimizer might even optimize the code away entirely.)
The Device
The device also uses if (0) and is trivial: you simply include a label that’s the target of a goto.
if (0) {
label:
// ... code ...
}
That’s it. What use is that? It allows a block of code to be executed only if explicitly gotod. Code before it won’t simply “fall into” it. The code also resumes the normal code flow.
We can rewrite the missing_arg example from the goto post to use the device:
void cli_options_init( int *pargc, char const **pargv[] ) {
// ...
for (;;) {
// ...
if ( option->has_arg == required_argument ) {
if ( optarg == NULL )
goto missing_arg;
SKIP_WS( optarg );
if ( optarg[0] == '\0' )
goto missing_arg;
}
// ...
switch ( opt ) {
// ...
case ':':
goto missing_arg;
}
}
// ...
//return; // This return is no longer needed
if (0) {
missing_arg:
fatal_error( EX_USAGE,
"\"%s\" requires an argument\n",
get_opt_format( opt == ':' ? optopt : opt )
);
}
}
A Macro
While the device works as-is, it’s a bit ugly. As it often the case, we can use a preprocessor macro to hide the ugliness:
#define only_if(LABEL) if (0) LABEL:
Then:
only_if ( missing_arg ) {
fatal_error( EX_USAGE,
"\"%s\" requires an argument\n",
get_opt_format( opt == ':' ? optopt : opt )
);
}
The “only if” means that the code will be executed only if an option is missing its required argument.
Notice that the position of the label is now before the {. It’s completely equivalent because a compound statement of { ... } is a statement and C allows you to put a label before any statement.
switch
You can also use the device in switch statements just like Duff’s:
switch ( c ) {
only_if ( case '\0' ) {
// ...
}
only_if ( case '=' ) {
// ...
}
only_if ( default ) {
// ...
}
}
Doing so allows you to eliminate the breaks between cases. This works because a case or default label is a label syntactically.
Should you actually do this in production code? Probably not. Even if you dislike that C “falls through” into the next case, code using such a macro is likely more confusing for the uninitiated than C’s normal and well-known behavior. I only wanted to show that the device can be used in a switch for curiosity.
Conclusion
Clifford’s (or Claire’s) Device is another quirky “feature” of C in that you can goto into a compound statement at any point. It has a marginal use when used with a goto; less so with switch.
Use wisely.
Top comments (0)