DEV Community

Paul J. Lucas
Paul J. Lucas

Posted on

Clifford’s (aka, Claire’s) Device in C and C++

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
Enter fullscreen mode Exit fullscreen mode

As another alternative, you can instead do:

if (0) {
  // ... disabled block of code ...
}
Enter fullscreen mode Exit fullscreen mode

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 ...
  }
Enter fullscreen mode Exit fullscreen mode

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 )
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

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:
Enter fullscreen mode Exit fullscreen mode

Then:

  only_if ( missing_arg ) {
    fatal_error( EX_USAGE,
      "\"%s\" requires an argument\n",
      get_opt_format( opt == ':' ? optopt : opt )
    );
  }
Enter fullscreen mode Exit fullscreen mode

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 ) {
    // ...
  }
}
Enter fullscreen mode Exit fullscreen mode

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)