Monthly Archives: October 2019

Braces! Foiled again!

Here’s another quick C programming thing.

Consider the following code, which nest two for/next loops together. Notice the variable it uses for each one.

for (int i=0 ; i < 10; i++) // using i
{
    printf("%d\n", i);

    for (int i=0 ; i < 3 ; i++) // using i
    {
        printf ("   %d\n", i);
    }
}

What do you think it will print? Will this even work? Running it produces…

0
   0
   1
   2
1
   0
   1
   2
2
   0
   1
   2
3
   0
   1
   2
4
   0
   1
   2
5
   0
   1
   2
6
   0
   1
   2
7
   0
   1
   2
8
   0
   1
   2
9
   0
   1
   2

In C, you create a new instance (scope) of a variable “i” within the braces. The second for/next declares its own local i, and any references to i within those braces will be that second instance of i.

This is confusing, of course, but it works.

A “bug” could exist if the second scope forgot the “int”:

for (int i=0 ; i < 10; i++) // using i
{
    printf ("%d\n", i);

    for (i=0 ; i < 3 ; i++) // where's the int?
    {
        printf ("   %d\n", i);
    }
}

By forgetting that “int”, it re-uses the first instance of i, and does not do what was expected.

0
   0
   1
   2
4
   0
   1
   2
4
   0
   1
   2
4
   0
   1
   2
4
   0
   1
   2
4
...repeat...

This was based on something recently fixed in some production code at my day job.

So, yeah. Use different variable names and avoid this from ever happening.

Next, revisiting a recent post, also dealing with what braces do, I stumbled upon a much better reason to always put braces around things, even if it’s just one statement.

Suppose you had a simple DEBUG macro (this is not a good one, but pretend it is):

#define DEBUG(x) printf(x);

if (x==1) DEBUG("hello");

Looks fine! But if you decide to make the macro contain multiple statements, using the backslash character like this:

#define DEBUG(x) printf("ERROR!\n"); \ printf(X);

It now breaks. That macro changes the resulting code into something like this:

if (x==1) printf("ERROR!\n");
printf("hello");

Not what was expected. To solve this, the macro creator should have put the statements in braces like:

#define DEBUG(x) { printf("ERROR!\n"); \ printf(X); }

Problem solved. Assuming the macro creator did it that way.

So, to prevent things like this that look fine and work fine from doing neither, just get in the habbit of using braces even for one statement:

if (x==1) { DEBUG("hello"); }

Or just always do them in multiple lines:

if (x==1)
{
   DEBUG("hello");
}

…and you don’t ever have to worry about that again.

Until next time…