views:

326

answers:

7

Hi,

I am confused about this code: (http://www.joelonsoftware.com/articles/CollegeAdvice.html)

while (*s++ = *t++);

What is the order of execution? Is *s = *t first done, and then are they each incremented? Or other way around?

Thanks.

EDIT: And what if it was:

while(*(s++) = *(t++));

and

while(++*s = ++*t);
+2  A: 

The increment is a post-increment. Post not just because it comes after the variable being incremented, but also because it comes after the expression is evaluated. So the order of execution is

*s = *t

then s++ and t++

Doug T.
+1  A: 

EDIT::

@chrisgoyal

Order of execution is an ambiguous term. There are two different things here. The syntactical order, and the semantics of the expression.

Syntactically, the operator ++ is applied first. If the *s is applied first, then the following is equivalent to what @Hogan said:

(*s)++ = (*t)++

Which is very different from Joel's sample.

The semantics of the operator ++ is that it is executed after the expression.

Hope that clarifies what I meat.


Actually, s++ and t++ are applied first. Don't forget that the post-fix operator is executed after the expression is done. Basically the operator ++ is applied for both, then *s = *t is executed.

AraK
err... after means after right. You described the increment happening before.
Hogan
@Hogan the post-fix operator is of **higher priority**, so it is applied first. The *semantics* of the post-fix operator is applied *after* the expression is done.
AraK
Your answer says two different things...
chrisgoyal
Not exactly. `++` (either pre- or postfix) is higher precedence than `=`, so it "happens" first - it's just that postfix `++` returns the _old_ value rather than the newly incremented one. When the operations actually happen in the machine code is irrelevant.
Chris Lutz
@Arak: Totally clear now... -1 banished. (Tho w/ over 16k, not sure it is such a big deal.)
Hogan
+4  A: 

You are right. *s = *t is done first, and then they are incremented.

Moron
A: 

In Post increment operation variable is used first and then after its gets modified.

Ashish
+13  A: 
while (*s++ = *t++);

From the precedence table you can clearly see ++ is having higher precedence than *. But ++ is used here as post increment operator, so the incrementation happens after the assignment expression. So *s = *t happens first, then s and t are incremented.

EDIT:

while(*(s++) = *(t++));

Is same as above. You are making it more explicit with the use of parenthesis. But remember ++ is still a post increment.

while(++*s = ++*t);

There is just one operator next to s. So * is applied first and on that result ++ is applied which results in the lvalue required error.

while(*++s = *++t);

Again just operator next to s,t. So the incrementation happens first followed by copy. So we are effectively skipping the copy of the first char from t to s.

codaddict
Isn't it "precedence" and not "precedance"? It might be some British/American thing, so I don't want to edit...
Thomas Padron-McCarthy
Thanks Thomas :)
codaddict
A: 

So there are two forms of increment

++s // increment before using value
s++ // increment after using value

And the result of these can be dereferenced:

*++s // or...
*s++

This worked out really well on one of the very first machines for C to run on, the PDP-11, which had a register-indirect addressing mode that increment the register after. The following ops were available in hardware:

*--s // or
*s++

You could do either

*x++ = *y++; // or
*--x = *--y; // or some combination

And if you did, the whole line happened in a single instruction. Since // comments were introduced by C99, however, you couldn't actually get away with my comment syntax.

DigitalRoss
You can get away with `//` comments using 99% of C compilers. It's not a good idea, but I doubt it'll kill anyone.
Chris Lutz
As usual, you are right, and I agree completely, but I was speculating that they would not have worked on the PDP-11 C compiler...
DigitalRoss
A: 

The code: (while *s++ = *t++); is roughly equivalent to:

while (*s = *t) {
    ++s;
    ++t;
}

The second is exactly the same -- the extra parens don't change anything (in this case). For the parens to do anything, they'd have to be like: while ((*s)++ = (*t)++);. This would do roughly the same as your third example (covered in the paragraph below).

The last example: while(++*s = ++*t); is completely different. Since the dereference (*) is closer to the operand, this dereferences the operand, and increments the result of the dereference, which means it increments what the pointer points AT, instead of incrementing the pointer itself. As a result, this would copy the first character, then increment that character, then check whether that character was non-zero and continue the same until it was zero. The result would be both the source and the destination becoming empty strings (since the first character of both would now be a zero, which is used to terminate strings).

Jerry Coffin