You've gotten the answer from the C Standard, but let's also think about why the definition is the way it is, why the expression *char_ptr++ -= 0x20
does not increment char_ptr
twice.
Suppose I had a null-terminated array of characters (as in fact the original code does), and suppose I wanted to subtract 0x20
from each character (which is similar to what the original code is doing). I might write
while(*char_ptr)
*char_ptr++ -= 0x20;
Now, even before we figure out exactly what this code does, certain things jump out at us. In particular, the while(*char_ptr)
part and the char_ptr++
part immediately tell us that this code is looping over the characters until it hits a null (or zero) character -- in other words, it is looping over the characters of a string. This is an extremely common idiom in C code.
And in this case, what it's doing with each character of the string is of course subtracting the value 0x20
from it.
So if the expression *char_ptr++ -= 0x20
did end up incrementing char_ptr
twice, this code wouldn't work! And that would be sad. So it's good that the definition of the -=
operator (and indeed the definition of all the "op=" operators) is that the left-hand side is evaluated only once. And it's no coincidence that they were defined this way, either -- they're defined this way precisely so that code like this works as expected.
While we're at it, let's look at a couple of other aspects of the original code.
What are those magic numbers 0x41
and 0x5A
? Well, in ASCII, 0x41
is capital A, and 0x5A
is capital Z. There's a school of thought that says you can't do C programming without an ASCII table handy, but in fact, laboriously looking up such codes us unnecessary extra work, because the compiler is perfectly willing to do it for us. We can write
if (*char_ptr < 'A')
and
if (*char_ptr > 'Z')
and we'll get the same result, with the added benefits that (a) the code is clearer and easier to read and (b) it's that much more portable to some hypothetical machine that doesn't use ASCII.
The magic number 0x20
that's being subtracted from the lower-case letters is the difference between a lower-case A and a capital A. (In ASCII, lower-case A is 0x61
.) So if you've got a lower-case letter, subtracting 0x20
turns it into the corresponding upper-case letter. So it looks like the code in the question is misnamed: It's actually converting to upper case, not lower case. (It's also going to mistakenly convert certain other characters, since anything greater than Z is converted, which will include punctuation characters like '['
and '|'
.)
Finally, since the expression we've been talking about is the only part of the code that increments char_ptr
, and since it acts only for non-upper-case characters, if the input contains any upper-case letters, char_ptr
won't get incremented even once, and this code will get stuck in an infinite loop.