Beautify your legacy C code layout for "free"

When I read code, it often strikes me how an unexpected code layout can slow me down and waste my time. I quickly develop a rash when I come across C code formatted like this:

void command_Ping(Transaction_t* RequestIn,
    Transaction_t* RequestOut)

    SomeStruct_t *Input;
    VeryDifferrentStruct_t* Output   ;
    DataIn_t DataInput;
    MyData_t* DataTest;
   int SampleLoop=1, OuterLoop, InnerLoop;
    static Bit16_t  SampleNumber  =0;
    Output = (VeryDifferrentStruct_t*) &RequestOut->Param;
   if ((RequestIn->Param2 & HIGH)== HIGH)
#ifdef SIM /* Applicable for simulator */
    } else {
   if ((RequestIn->Param2 & LOW) ==LOW)

But if you work with a legacy system, you can't improve the above code, because *any* code change in a system without automated tests comes with a severe penalty: extensive, manual regression testing.
So we don't fix it, and the ugly code stays in the system forever, awaiting the next unsuspecting developer that comes along.  Over time, both you and the system become increasingly miserable.

But wait, there is hope!! The reason we don't change ugly code layout by hand is the risk of introducing new bugs, right? What if there was a guaranteed bug-proof way to change source code layout? Then we could safely drop the expensive manual regression test, and legacy systems would see a brighter future :-) Yeah!

As you may have guessed by now, the secret is to let an automated "indenter" tool make the layout changes, through whitespace removal/adding. Assuming that the tool itself is bug-free, the code that comes out of the tool will look unchanged to the C compiler, i.e. containing exactly the same bugs as the original code, and no new ones. But to you and me, the code will look much more in line with our expectations for cleanly written C code:

void command_Ping(Transaction_t *RequestIn,
                  Transaction_t *RequestOut){

    SomeStruct_t           *Input;
    VeryDifferrentStruct_t *Output;
    DataIn_t               DataInput;
    MyData_t               *DataTest;
    int                    SampleLoop   = 1, OuterLoop, InnerLoop;
    static Bit16_t         SampleNumber = 0;

    Input  = (SomeStruct_t *) &RequestIn->Param;
    Output = (VeryDifferrentStruct_t *) &RequestOut->Param;

    if ((RequestIn->Param2 & HIGH) == HIGH) {
#ifdef SIM /* Applicable for simulator */
        CallSim(&RequestIn->Param, &OuterLoop, LOOP & 8);
        memcpy(Output, Input, PACKET_PARAM_SIZE / 2);
    else {
        if ((RequestIn->Param2 & LOW) == LOW) {

    RequestOut->Length = RequestIn->Length - 6;

(OK,  maybe your expectations are different from mine, but the code is easier to read now)

Spoiler: The above code transformation was produced by the open-source tool Uncrustify, using a settings file I generated after some hours of tweaking 350+ Uncrustify settings in UniversalIndentGUI. (Wikipedia)

The beautifier tools I've looked into typically spend a fraction of a second on improving a large C program. So basically, if you point the tool to your large C/C++ system, all .c, .cpp, .hh and .h files will be beautified in less time than it takes you to finish lunch. All that is left for you is to check the improved sources back into your CVS. No regression testing required!

And it gets better: regardless of your platform (Linux, Mac,Windows), you will find high-quality open-source C/C++ beautifiers on the www. To cut your chase short, I strongly recommend you to download and install the "meta tool" UniversalIndentGUI, as it will enable you to try out the 20+  different beautifiers it comes bundled with (e.g. Uncrustify, GreatCode, BCPP, GNU Indent, and others).
And most importantly, UniversalIndentGUI will allow you to see the immediate effect on source code layout as you tweak the numerous settings offered by the different tools. The interactive process UniversalIndentGUI offers for exploring settings will save you hours, as you work on the settings for your preferred layout.

When you are happy with the results in UniversalIndentGUI, simply export the settings file, and point your selected beautifier to it. (Or you can freely grab my Uncrustify settings file here. Tested with Uncrustify 0.53)

No code layout or style will please everyone in a team of developers, but with an automated beautifier, you can significantly improve source code readabilty in legacy systems, (almost) for free.

Happy beautifying!

No comments:

Post a Comment