*p++ = *q++ undefined? why?

F

fctk

hello,

i'm trying to understand what are the rules for determining when an
expression is well defined or not. i found a page
(http://c-faq.com/expr/seqpoints.html) which seems to explain this well
enough.

first of all some terms:
* object = variable, element of an array, location pointed by a pointer
* modification = assignment ( = += ... ), increment/decrement
(postfixed/prefixed)

if i understood correctly, there are two rules (checked in that order):
1) each object in an expression can be modified no more than once;
2) if an object is modified, then all the times that object is accessed
in order to be read, the values that are read must be all used for
calculating the final value of the object.

now give a look at the expression at http://c-faq.com/expr/confused.html
(end of point 3):

*p++ = *q++

i can't understand the following sentence:

"[...] in which three things are modified (p, q, and *p [...]), are
allowed if all three objects are distinct, i.e. only if two different
pointers p and q [...] are used."

i explain you my reasoning. first of all that expression could be
rewritten as:

((*(p++)) = (*(q++)))

there are 4 objects: p, q, *(p++), *(q++).

p, q and *(p++) are modified only once, so they follow rule 1.
*(q++) is not modified, so it also follows rule 1.

p is read only once, and the value of this reading is used for
calculating the final value of p, so rule 2 is respected. the same for
q. *(p++) is never read, so it also respects rule 2.

so, why that expression is undefined?

to be honest, it does not say it is "undefined", but it speaks about
being allowed or not. so: in which case this expression is not allowed?
i can't see when...

also, the compiler (gcc) does not complain as in:

i = i++ /* warning: operation on `i' may be undefined */

so, what's the problem?
 
V

Vladimir S. Oka

fctk said:
hello,

i'm trying to understand what are the rules for determining when an
expression is well defined or not. i found a page
(http://c-faq.com/expr/seqpoints.html) which seems to explain this
well enough.

first of all some terms:
* object = variable, element of an array, location pointed by a
pointer * modification = assignment ( = += ... ), increment/decrement
(postfixed/prefixed)

if i understood correctly, there are two rules (checked in that
order): 1) each object in an expression can be modified no more than
once; 2) if an object is modified, then all the times that object is
accessed in order to be read, the values that are read must be all
used for calculating the final value of the object.

now give a look at the expression at
http://c-faq.com/expr/confused.html (end of point 3):

*p++ = *q++

i can't understand the following sentence:

"[...] in which three things are modified (p, q, and *p [...]), are
allowed if all three objects are distinct, i.e. only if two different
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
^^^^^^^^

Here's the key to understanding this. The assignment is well defined
*only* if `p` and `q` point to different objects in memory. If they
point to the same object you get undefined behaviour.

That is probably the reason for compiler not emitting a diagnostic, as
there are circumstances when above is OK.

Anyway, don't do that.
pointers p and q [...] are used."

i explain you my reasoning. first of all that expression could be
rewritten as:

((*(p++)) = (*(q++)))

there are 4 objects: p, q, *(p++), *(q++).

p, q and *(p++) are modified only once, so they follow rule 1.
*(q++) is not modified, so it also follows rule 1.

p is read only once, and the value of this reading is used for
calculating the final value of p, so rule 2 is respected. the same
for q. *(p++) is never read, so it also respects rule 2.

so, why that expression is undefined?

to be honest, it does not say it is "undefined", but it speaks about
being allowed or not. so: in which case this expression is not
allowed? i can't see when...

also, the compiler (gcc) does not complain as in:

i = i++ /* warning: operation on `i' may be undefined */

so, what's the problem?

--
My theology, briefly, is that the universe was dictated but not
signed.
-- Christopher Morley

<http://clc-wiki.net/wiki/Introduction_to_comp.lang.c>
 
C

Charles Krug

hello,

i'm trying to understand what are the rules for determining when an
expression is well defined or not. i found a page
(http://c-faq.com/expr/seqpoints.html) which seems to explain this well
enough.

now give a look at the expression at http://c-faq.com/expr/confused.html
(end of point 3):

*p++ = *q++

i can't understand the following sentence:

"[...] in which three things are modified (p, q, and *p [...]), are
allowed if all three objects are distinct, i.e. only if two different
pointers p and q [...] are used."



i explain you my reasoning. first of all that expression could be
rewritten as:

((*(p++)) = (*(q++)))

there are 4 objects: p, q, *(p++), *(q++).

That's not the same expression at all.
i = i++ /* warning: operation on `i' may be undefined */

so, what's the problem?

That's not the same expression as in the FAQ at all.

I'm not certain why you'd ever write code like that, but I can't see
there that expression would create those sorts of problems (IANALL)
 
M

Michael Mair

fctk said:
hello,

i'm trying to understand what are the rules for determining when an
expression is well defined or not. i found a page
(http://c-faq.com/expr/seqpoints.html) which seems to explain this well
enough.

first of all some terms:
* object = variable, element of an array, location pointed by a pointer
* modification = assignment ( = += ... ), increment/decrement
(postfixed/prefixed)

if i understood correctly, there are two rules (checked in that order):
1) each object in an expression can be modified no more than once;
2) if an object is modified, then all the times that object is accessed
in order to be read, the values that are read must be all used for
calculating the final value of the object.

now give a look at the expression at http://c-faq.com/expr/confused.html
(end of point 3):

*p++ = *q++

i can't understand the following sentence:

"[...] in which three things are modified (p, q, and *p [...]), are
allowed if all three objects are distinct, i.e. only if two different
pointers p and q [...] are used."

There are two possible interpretations:
- p == q is not allowed,
- &p == &q is not allowed, e.g. we must not write
*p++ = *p++

For the following I assume p != 0, q != 0.
i explain you my reasoning. first of all that expression could be
rewritten as:

((*(p++)) = (*(q++)))

there are 4 objects: p, q, *(p++), *(q++).

Let us keep this even easier:
p, q, *p, *q
p, q and *(p++) are modified only once, so they follow rule 1.
*(q++) is not modified, so it also follows rule 1.

If p!=q, i.e. p and q point to different objects, then you
could "implement" the above by
1) copying *q to tmp
2) increasing q by one
3) copying p to ptmp
4) increasing p by one
5) copying tmp to *ptmp and "returning" tmp
which we can reorder to 1-3-2-4-5, 1-3-4-2-5, 3-4-1-2-5, 3-1-4-2-5,
3-1-2-4-5 without breaking it.
If we assume p==q, we cannot break this.
Only if we replace "q" by "p", then everything not starting with 1)
and 3) in the first two positions breaks.
p is read only once, and the value of this reading is used for
calculating the final value of p, so rule 2 is respected. the same for
q. *(p++) is never read, so it also respects rule 2.

so, why that expression is undefined?

I guess that the second interpretation is meant.
Reading the whole item 3. from the page implies that "difference"
really is not meant in the sense p != q but in the sense &p != &q.
to be honest, it does not say it is "undefined", but it speaks about
being allowed or not. so: in which case this expression is not allowed?
i can't see when...

also, the compiler (gcc) does not complain as in:

i = i++ /* warning: operation on `i' may be undefined */

so, what's the problem?

HTH
Michael
 
F

fctk

Michael Mair ha scritto:
There are two possible interpretations:
- p == q is not allowed,
- &p == &q is not allowed, e.g. we must not write
*p++ = *p++

[...]

I guess that the second interpretation is meant.
Reading the whole item 3. from the page implies that "difference"
really is not meant in the sense p != q but in the sense &p != &q.

of course *p++ = *p++ is undefined, becouse the same object (p) is
modified two times in the same expression, and this is not allowed by
rule 1.

i also made this program:

#include <stdio.h>

int main(void) {

int a[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int *p, *q;

p = q = a;

printf("%d %d %d\n", *p, *q, a[0]);

*(p++) = *(q++);

printf("%d %d %d\n", *p, *q, a[0]);

return 0;

}

and i get the following output (as expected):

0 0 0
1 1 0

i can't really imagine other possible results...
 
M

Michael Mair

Vladimir said:
hello,

i'm trying to understand what are the rules for determining when an
expression is well defined or not. i found a page
(http://c-faq.com/expr/seqpoints.html) which seems to explain this
well enough.

first of all some terms:
* object = variable, element of an array, location pointed by a
pointer * modification = assignment ( = += ... ), increment/decrement
(postfixed/prefixed)

if i understood correctly, there are two rules (checked in that
order): 1) each object in an expression can be modified no more than
once; 2) if an object is modified, then all the times that object is
accessed in order to be read, the values that are read must be all
used for calculating the final value of the object.

now give a look at the expression at
http://c-faq.com/expr/confused.html (end of point 3):

*p++ = *q++

i can't understand the following sentence:

"[...] in which three things are modified (p, q, and *p [...]), are
allowed if all three objects are distinct, i.e. only if two different

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
^^^^^^^^

Here's the key to understanding this. The assignment is well defined
*only* if `p` and `q` point to different objects in memory. If they
point to the same object you get undefined behaviour.

Probably I am too coffee-deprived to think clearly but at the moment
I can see nothing but an "a=a" type assignment with side effect free
"a" for this case even with my worst imagination at work...

Cheers
Michael
 
S

stathis gotsis

fctk said:
Charles Krug ha scritto:


why *p++ = *q++ is not the same of ((*(p++)) = (*(q++))) ?

I have no idea, they must be the same according to operator precedence.
 
P

pete

fctk said:
Michael Mair ha scritto:
There are two possible interpretations:
- p == q is not allowed,
- &p == &q is not allowed, e.g. we must not write
*p++ = *p++

[...]

I guess that the second interpretation is meant.
Reading the whole item 3. from the page implies that "difference"
really is not meant in the sense p != q but in the sense &p != &q.

of course *p++ = *p++ is undefined, becouse the same object (p) is
modified two times in the same expression,

That's not what you said before:

"p, q and *(p++) are modified only once, so they follow rule 1.
*(q++) is not modified, so it also follows rule 1."

(p) is the operand of a ++ operator
(q) is the operand of a ++ operator
(*p) is the left operand of a = operator
(*q) is the right operand of a = operator

Those 4 expressions refer to 4 different objects.
 
P

pete

Michael said:
hello,

i'm trying to understand what are the rules for determining when an
expression is well defined or not. i found a page
(http://c-faq.com/expr/seqpoints.html) which seems to explain this
well enough.

first of all some terms:
* object = variable, element of an array, location pointed by a
pointer * modification = assignment ( = += ... ), increment/decrement
(postfixed/prefixed)

if i understood correctly, there are two rules (checked in that
order): 1) each object in an expression can be modified no more than
once; 2) if an object is modified, then all the times that object is
accessed in order to be read, the values that are read must be all
used for calculating the final value of the object.

now give a look at the expression at
http://c-faq.com/expr/confused.html (end of point 3):

*p++ = *q++

i can't understand the following sentence:

"[...] in which three things are modified (p, q, and *p [...]), are
allowed if all three objects are distinct,
i.e. only if two different

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
^^^^^^^^

Here's the key to understanding this. The assignment is well defined
*only* if `p` and `q` point to different objects in memory. If they
point to the same object you get undefined behaviour.

Probably I am too coffee-deprived to think clearly but at the moment
I can see nothing but an "a=a" type assignment with side effect free
"a" for this case even with my worst imagination at work...

As long as (*p) is defined and (*q) is defined,
there is nothing wrong with (*p++ = *q++).
 
C

CBFalconer

pete said:
.... snip ...

As long as (*p) is defined and (*q) is defined,
there is nothing wrong with (*p++ = *q++).

Assuming p != q.

--
"If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers." - Keith Thompson
More details at: <http://cfaj.freeshell.org/google/>
Also see <http://www.safalra.com/special/googlegroupsreply/>
 
F

fctk

Vladimir S. Oka ha scritto:
fctk said:
now give a look at the expression at
http://c-faq.com/expr/confused.html (end of point 3):

*p++ = *q++

i can't understand the following sentence:

"[...] in which three things are modified (p, q, and *p [...]), are
allowed if all three objects are distinct, i.e. only if two different

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
^^^^^^^^

Here's the key to understanding this. The assignment is well defined
*only* if `p` and `q` point to different objects in memory. If they
point to the same object you get undefined behaviour.

That is probably the reason for compiler not emitting a diagnostic, as
there are circumstances when above is OK.

Anyway, don't do that.

i can't really understand *why* i get undefined behaviour if `p` and `q`
point to the same object in memory.
 
M

Michael Mair

pete said:
Michael said:
Vladimir said:
fctk <-> opined:



hello,

i'm trying to understand what are the rules for determining when an
expression is well defined or not. i found a page
(http://c-faq.com/expr/seqpoints.html) which seems to explain this
well enough.

first of all some terms:
* object = variable, element of an array, location pointed by a
pointer * modification = assignment ( = += ... ), increment/decrement
(postfixed/prefixed)

if i understood correctly, there are two rules (checked in that
order): 1) each object in an expression can be modified no more than
once; 2) if an object is modified, then all the times that object is
accessed in order to be read, the values that are read must be all
used for calculating the final value of the object.

now give a look at the expression at
http://c-faq.com/expr/confused.html (end of point 3):

*p++ = *q++

i can't understand the following sentence:

"[...] in which three things are modified (p, q, and *p [...]), are
allowed if all three objects are distinct,
i.e. only if two different

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
^^^^^^^^

Here's the key to understanding this. The assignment is well defined
*only* if `p` and `q` point to different objects in memory. If they
point to the same object you get undefined behaviour.

Probably I am too coffee-deprived to think clearly but at the moment
I can see nothing but an "a=a" type assignment with side effect free
"a" for this case even with my worst imagination at work...

As long as (*p) is defined and (*q) is defined,
there is nothing wrong with (*p++ = *q++).

Thank you :)
Michael
 
V

Vladimir S. Oka

Eric Sosman opined:
Even if p == q. (Confession: I very nearly made
the same mistake.)

Now I can see it as well! Apologies for the confusion.

Now that I actually thought it through, isn't the above the very
construct K&R use to implement `strcpy()`? I left my copy at work, so
I can't look it up, but I'm pretty sure. Along the lines of:

while (*p++ = *q++)
;
 
C

Chris Torek

[some snippage; but it starts with:]
[and ends with:]

i can't really understand *why* i get undefined behaviour if `p` and `q`
point to the same object in memory.

You do not (get undefined behavior). If p and q are both valid and
both point to some suitable object(s), the statement:

*p++ = *q++

has well-defined behavior, copying the value at *q to the object
named by *p, and incrementing both p and q.

Go back and re-read the web page named above, and look at "point 3"
again. It says that:

*p++ = *q++;

is OK, but:

*p++ = *p++; /* WRONG */

is *not* OK. More precisely, it says:

"... only if two different pointers p and q ... are used"

by which the FAQ means "do not use one single variable, p and p".
 
P

pete

Vladimir said:
Eric Sosman opined:


Now I can see it as well! Apologies for the confusion.

Now that I actually thought it through, isn't the above the very
construct K&R use to implement `strcpy()`? I left my copy at work, so
I can't look it up, but I'm pretty sure. Along the lines of:

while (*p++ = *q++)
;

Yes.
/* strcpy: copy t to s; pointer version 3 */
void strcpy(char *s, char *t)
{
while (*s++ = *t++)
;
}

You can see how that implementation of strcpy
would be undefined with something like:

char char_array[] = "xx\0";

strcpy(char_array, char_array + 1);

though

memmove(char_array, char_array + 1, 1 + strlen(char_array + 1));

would be fine.
 
P

pete

pete said:
Eric Sosman opined:


Now I can see it as well! Apologies for the confusion.

Now that I actually thought it through, isn't the above the very
construct K&R use to implement `strcpy()`? I left my copy at work, so
I can't look it up, but I'm pretty sure. Along the lines of:

while (*p++ = *q++)
;

Yes.
/* strcpy: copy t to s; pointer version 3 */
void strcpy(char *s, char *t)
{
while (*s++ = *t++)
;
}

You can see how that implementation of strcpy
would be undefined with something like:

char char_array[] = "xx\0";

strcpy(char_array, char_array + 1);

though

memmove(char_array, char_array + 1, 1 + strlen(char_array + 1));

would be fine.

I think instead those examples should be:

char char_array[] = "xx\0";

strcpy(1 + char_array, char_array);

though

memmove(1 + char_array, char_array, 1 + strlen(char_array));

would be fine.
 
M

Michael Mair

pete said:
Vladimir said:
Eric Sosman opined:

Now I can see it as well! Apologies for the confusion.

Now that I actually thought it through, isn't the above the very
construct K&R use to implement `strcpy()`? I left my copy at work, so
I can't look it up, but I'm pretty sure. Along the lines of:

while (*p++ = *q++)
;

Yes.
/* strcpy: copy t to s; pointer version 3 */
void strcpy(char *s, char *t)
{
while (*s++ = *t++)
;
}

You can see how that implementation of strcpy
would be undefined with something like:

char char_array[] = "xx\0";

strcpy(char_array, char_array + 1);

though

memmove(char_array, char_array + 1, 1 + strlen(char_array + 1));

would be fine.

Why? How? I cannot see anything undefined in that.
If you wrote "strcpy(char_array + 1, char_array);", then I would
agree.
strcpy() called for overlapping objects invokes UB by both
standards, yes. But the above implementation IMO is safe for
two out of three kinds of overlapping (i.e. t==s and t>s but not
t<s).


Cheers
Michael
 
P

pete

Michael said:
Vladimir said:
Eric Sosman opined:
CBFalconer wrote:
pete wrote:

... snip ...

As long as (*p) is defined and (*q) is defined,
there is nothing wrong with (*p++ = *q++).

Assuming p != q.

Even if p == q. (Confession: I very nearly made
the same mistake.)

Now I can see it as well! Apologies for the confusion.

Now that I actually thought it through, isn't the above the very
construct K&R use to implement `strcpy()`? I left my copy at work, so
I can't look it up, but I'm pretty sure. Along the lines of:

while (*p++ = *q++)
;

Yes.
/* strcpy: copy t to s; pointer version 3 */
void strcpy(char *s, char *t)
{
while (*s++ = *t++)
;
}

You can see how that implementation of strcpy
would be undefined with something like:

char char_array[] = "xx\0";

strcpy(char_array, char_array + 1);

though

memmove(char_array, char_array + 1, 1 + strlen(char_array + 1));

would be fine.

Why? How? I cannot see anything undefined in that.
If you wrote "strcpy(char_array + 1, char_array);", then I would
agree.

That's what I meant write.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,537
Members
45,020
Latest member
GenesisGai

Latest Threads

Top