6

I had this question after reading the Stack Overflow quesion Print an int in binary representation using C.

In a user's comment, they posted this for loop, which assigns either a 1 or a 0 to the bit position in order to convert from an int decimal to char * binary.

for(; bits--; u >>= 1)
    str[bits] = u & 1 ? '1' : '0';

I understand why there doesn't need to be an initialized value. This is the syntax for a for loop that I've always known:

for ( variable initialization; condition; variable update )

I don't understand how 'bit--' can be an exit condition. Please help me understand how this code works (I tested it, and it is valid).

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Lolo_Fsho
  • 61
  • 1
  • 3
  • 2
    This is what C programmers are cursed for!! Producing code that does something but no one understands it anymore. Don't try to write code like that!! bits-- decrements the bits variable, once it is zero, it returns false – guitarflow Feb 09 '12 at 00:59
  • 1
    @guitarflow Those who understand C and its idioms understand such code just fine as this very common in C code (including the K&R book), and I would say that this idiom must be learned to understand C code in general. So why should new code (in any language) be written for those who do _not_ understand the language? The more “universally understandable” form may even complicate things for a reader fluent in the language, i.e., “why didn't he use [common idiom], is there something I'm missing?” – Arkku Feb 09 '12 at 01:08
  • @Arkku I also understand the code, but you must agree it's not good coding style. Writing the for-loop in a "standard" manner makes it more readable to anyone, not just the cracks. Variable names like "u" are also not a descriptive name ;) – guitarflow Feb 09 '12 at 01:11
  • 1
    @guitarflow I assumed you meant that `bits--` as a condition for termination was in bad style, which I don't agree with (although I might personally substitute `while` for `for` here). As for `u`, no, it's not descriptive but considering the simplicity of the code fragment it may not need to be... For example, if this is a routine to convert an uint to a string in base 2, what would you call `u` instead? Something like to `num_to_convert` would be far worse (misleading and ambiguous). Of course we don't know if this is part of such a function where `u` has such an obvious role. – Arkku Feb 09 '12 at 01:20
  • @Arkku I would maybe call it numSourceStr or something like that. I know that camel-case is not the K&R-style. I'm more on the "modern" side here, but I can live with that. – guitarflow Feb 09 '12 at 01:24
  • @guitarflow “numSourceStr” would also be misleading, as the name can be easily be read implying that the variable itself is a string that is the source of a number. Or, combined with the knowledge that the variable is an integer, that it contains the number of source strings. In any case, since the above code is essentially the complete function to convert an uint to string, I would argue that any long variable name will just make it _less_ readable by increasing the length, without contributing any information that is not immediately obvious from the purpose of the function itself. – Arkku Feb 09 '12 at 01:35

4 Answers4

9

In C, a value of zero evaluates to "false" in a Boolean context. So when bits-- evaluates to 0, in the context of the loop it evaluates to "false" and terminates the loop.

If you say, for example:

int x = 1;
if (--x)
{
  printf("True!\n");
}
else
{
  printf("False!\n");
}

It will output "False", because --x evaluates to 0, which is "false" in a Boolean context.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Charles Salvia
  • 52,325
  • 13
  • 128
  • 140
  • Ok, I had suspicions that that was the case. Thank you. – Lolo_Fsho Feb 09 '12 at 00:59
  • 4
    Charles, you are right, but --x is not the same as x--. If you change the code above to x--, it will print "True!". – Diego Feb 09 '12 at 01:04
  • @dfmx123, the difference between post-increment and pre-increment is another issue, and not really within the scope of the question here. The point is simply to demonstrate that expressions which evaluate to zero are considered "false" in a conditional context. – Charles Salvia Feb 09 '12 at 16:20
1

All conditions basically boil down to checking whether something is 0 or not. 0 means false, everything else means true. So that loop will break when bits is 0.

You will sometimes see while or if conditions written

if (variable) // or while(variable)

That is just shorthand for

if (variable != 0) // or while (variable != 0)

So

for (; bits--; u >>= 1) 

is short for

for (; bits-- != 0; u >>= 1)
Seth Carnegie
  • 73,875
  • 22
  • 181
  • 249
0

bits-- is an assignment expression of type int (since it will return the value of b, which is int). To match the for loop syntax, it gets converted to a Boolean expression, which means it is true if bits != 0.

In fact, the condition is identical to bits!=0, but by using bits--, it changes the value of bits at the same time, making the code more compact. That's all.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Diego
  • 18,035
  • 5
  • 62
  • 66
0

As others said, in C, you can use integers as a condition - 0 or false, and anything else for true. (Actually, you almost always do it - even an expression like a<b is an int.)

So, the loop will end when bits-- will be 0.

When the -- operator comes after the variable, it decreases the variable, and gets the previous value of it. For example, if you have int a=3,b; b=a--;, then b will be 3, and a will be 2.

So, the loop will exit after that bits will been decreased from 0 to -1.

That means that, if in the beginning, bits==8 (for example), the loop will iterate 8 times, when in the first, bits will be 7 (because the condition had checked), and in the last, bits will be 0. It is a nice way to loop through an array (Since in C, an array of bits variables is being indexed from 0 to bits-1).

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
asaelr
  • 5,438
  • 1
  • 16
  • 22