a[i] = x[a[i]]++

J

Joona I Palaste

Andrey Tarasevich said:
Joona said:
Someone also mentioned something along the lines of a[a]=i. This I
would consider defined behaviour, because what is being modified is
a[a], and its old value is never used in the expression at all.

In general case it is possible that a == i, in which case the problem
is rather obvious. This example is specifically targeted at this
particular situation.


If a==i, then the expression is equivalent to a=i. However, this
is still very much defined behaviour, as the object being modified is
a, and its old value is not actually used for anything at all in the
above code. Note that even though a==i that doesn't mean that
&(a)==&i, i.e. changing one won't affect the other.

--
/-- Joona Palaste ([email protected]) ------------- Finland --------\
\-------------------------------------------------------- rules! --------/
"'It can be easily shown that' means 'I saw a proof of this once (which I didn't
understand) which I can no longer remember'."
- A maths teacher
 
T

Thomas Stegen

Joona said:
Andrey Tarasevich said:
BRG said:
Does anyone here know whether the assignment:

a = x[ a ]++;

Yes it does, and no it is not. The old value of i is also being used as
an index to the x array. Therefore this caused undefined behaviour.

a = (*(x + a))++;

Why is the above so very different from "i = i + 3;"?
Point is, why is the index operator so different from the addition
operator?

i is read to be used as an operand for the addition operator.
a is read to be used as an operand for the index operator.
Then in both cases the result is written back.

If someone can explain to me how the addition operator can be used
to only determine the result to store while the index operator cannot
I would appreciate it.

An operator takes a set of operands and delivers a value. It seems to
me that in both cases the operands are read only to determine the
value of this operation.

The more I think about the surer I become that the above is defined.
The basic semantics for operators apply to all operators and I don't
see any differences in this case.

On the first sight, in this expression this requirement is met, i.e.
this expression is OK.


Of course the expression "a[a]=5" is OK.


Hint: a == i
However, on the second sight, one can argue that this expression
violates that "only" requirement: in this case the old value of 'i' is
read not only to determine its new value, but also to determine, which
element of 'x[]' to increment. Personally, I don't think this is a valid
argument (considering what I think was the intent), but I could be wrong.


If you were talking about "a[a]=5" above, then this is plain
nonsense.


If "this" refers to what you are saying you are correct.
 
B

BRG

Thomas said:
Joona said:
Andrey Tarasevich said:
BRG wrote:

Does anyone here know whether the assignment:

a = x[ a ]++;


Yes it does, and no it is not. The old value of i is also being used as
an index to the x array. Therefore this caused undefined behaviour.


a = (*(x + a))++;

Why is the above so very different from "i = i + 3;"?
Point is, why is the index operator so different from the addition
operator?


In my view its really the post-increment operation that needs to be
considered.

This is because, if the post-increment is the last thing done in
evaluating the right hand side (i.e it is done before a on the left
hand side is updated), then x[ old a ] will be post-incremented.

However, if the post-increment is the last thing done in evaluating the
whole expression (i.e it is done after a on the left hand side is
updated) then x[ new a ] will be post-incremented.

[snip]
Brian Gladman
 
J

Joona I Palaste

Thomas Stegen said:
Joona said:
Of course the expression "a[a]=5" is OK.

Hint: a == i


Hmm, now I think I see what people mean here. It's not i that matters
here, it's a. If a==i, then a is both assigned a new value and
used for computing something other than its new value, i.e. the value of
a[a].
 
A

Andrey Tarasevich

Joona said:
Andrey Tarasevich said:
Joona said:
Someone also mentioned something along the lines of a[a]=i. This I
would consider defined behaviour, because what is being modified is
a[a], and its old value is never used in the expression at all.

In general case it is possible that a == i, in which case the problem
is rather obvious. This example is specifically targeted at this
particular situation.


If a==i, then the expression is equivalent to a=i.


That's a pretty strong statement. It would be equivalent if one could be
sure that the original one does not produce UB.
However, this
is still very much defined behaviour, as the object being modified is
a, and its old value is not actually used for anything at all in the
above code.


Huh? What do you mean by "not used"? The expression 'a[a] = i', or
simply 'a[a] = 0' formally violates the requirements if the standard.
In general case it is possible that a == i, which means that this
expression modifies the value of 'a' object (outer 'a[]', assigns 0
to it) and at the same time reads its value (inner 'a[]'). It can't be
said that this act of reading is performed for the sole purpose of
determining the new value of the object, therefore it's UB.
Note that even though a==i that doesn't mean that
&(a)==&i, i.e. changing one won't affect the other.


It looks like you were looking in wrong direction. The problem is not
with 'i'. The problem is with 'a', which is modified and read at in
the same expression if a == i. The problem still exists, once again, in

a[a] = 0;
 
J

Joona I Palaste

Andrey Tarasevich said:
Joona said:
However, this
is still very much defined behaviour, as the object being modified is
a, and its old value is not actually used for anything at all in the
above code.

Huh? What do you mean by "not used"? The expression 'a[a] = i', or
simply 'a[a] = 0' formally violates the requirements if the standard.
In general case it is possible that a == i, which means that this
expression modifies the value of 'a' object (outer 'a[]', assigns 0
to it) and at the same time reads its value (inner 'a[]'). It can't be
said that this act of reading is performed for the sole purpose of
determining the new value of the object, therefore it's UB.


Ignore what I said. I thought about it a bit more and found out you were
right.
 
A

Andrey Tarasevich

BRG said:
...
This is because, if the post-increment is the last thing done in
evaluating the right hand side (i.e it is done before a on the left
hand side is updated), then x[ old a ] will be post-incremented.

However, if the post-increment is the last thing done in evaluating the
whole expression (i.e it is done after a on the left hand side is
updated) then x[ new a ] will be post-incremented.
...


It is not really about when the post-increment is done. It is about when
the _argument_ for the post-increment is determined.

If the compiler decides to evaluate 'x[a]' only once and use it as
argument for both assignment and post-increment, then the old value of
'a' is always used. The sequence of steps can be illustrated by the
following code sketch

p = &x[a] and then a = (*p)++

But if the compiler decides to re-evaluate the argument of the
post-increment then, of course, the new value of 'a' will be used

a = x[a] and then x[a]++
 
C

Christian Kandeler

Old said:
the standard is quite clear that in (a = b = 3.1),
a gets the value 3.1 even if b were an int.

Really? You should tell that to the gcc people, then:

$ cat > test.c
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
double a;
int b;

a = b = 3.1;

printf("a = %f\nb = %d\n", a, b);

return EXIT_SUCCESS;
}
^D
$ gcc -W -Wall -ansi -pedantic test.c
$ ./a.out
a = 3.000000
b = 3


Christian
 
R

Richard Bos

Christian Kandeler said:
Really? You should tell that to the gcc people, then:

Or to the C Standard committee:

# The type of an assignment expression is the type of the left operand
# unless the left operand has qualified type, in which case it is the
# unqualified version of the type of the left operand.
(From 6.5.16#3. Identical wording in C89.)

Richard
 
L

Lawrence Kirby

aegis said:
pete said:
aegis wrote:

The prior value of foo[3]
is used to determine the new value of foo[3],

Did you mean to say is /not/ used?

is

Then this is wrong.
The prior value of foo[3] in "bar[foo[3]]++"
is not used to determine the new value of
foo[3]. It is used to determine the element
of bar, which bar is used to determine the
new value of foo[3]

Yes. This means that, indirectly, foo[3] _is_ used to determine the new
value of foo[3]. The big question here is, is this indirect action
enough to save this from being undefined behaviour? To be honest, I
don't know the answer myself, but I know enough to see that it is far
from obvious.

If "indirect action" were not allowed then expressions like i = i + 1
would be undefined. I can see nothing in the standard that could be used
as a basis for a distinction between + and operators like = [] or ++ in
this respect. In particular there is no connection between the "only"
in 6.5p2 and side-effects if you accept that this is undefined
(void)((i = j) + i). Indeed I maintain that this sort of expression is the
real target of the word "only".

Lawrence
 
A

Albert van der Horst

Does anyone here know whether the assignment:

a = x[ a ]++;


I never use a statement like
x++;
on its own.
I always do the equivalent (barring the result value)
x += 1;
This shows that it is an assignment, rather than a side effect.
(The result of x++ is of course x, then it is thrown away,
oh and by the way, I have incremented x for you.
Extremely silly.)

Now the above is using the side effect,
to mix up in one statement
new = x[ old ];
x[ old ] += 1;

It is *not* equivalent to
a = x[ a ] += 1;
because, being a post-increment, the original value of
x[ a ] must be used.

This is valid, but is more appropriate for iocc than
supposedly maintainable code. There couldn't be a problem,
because there is nothing that is changed twice between the
sequence points, neither x[ old ] nor a .
is legal in C and, if so, what array element in x[] is post incremented?

That is, does the old or the new value of a determine the index in
x[] of the post incremented array element.

I rather suspect the result is undefined - but am I right?


Because the optimiser got confused?
Brian Gladman



--
 
P

Peter Nilsson

Albert said:
Does anyone here know whether the assignment:

a = x[ a ]++;


I never use a statement like
x++;
on its own.
Why?!

I always do the equivalent (barring the result value)
x += 1;
This shows that it is an assignment, rather than a side effect.


Rather poor reasoning since x++ is idiomatic, and because _all_
statements are _only_ evaluated for their side effects,
assignments or otherwise (e.g. function calls.)
(The result of x++ is of course x, then it is thrown away,
oh and by the way, I have incremented x for you.
Extremely silly.)

Yes, ": @++ dup @ dup 1+ over ! ;" _is_ silly, but only because
Forth is silly. ;)
 
A

Andrey Tarasevich

Albert said:
Does anyone here know whether the assignment:

a = x[ a ]++;


I never use a statement like
x++;
on its own.
I always do the equivalent (barring the result value)
x += 1;
This shows that it is an assignment, rather than a side effect.


The assignment itself is also a side effect. What you do is in no way
different from using the increment.
(The result of x++ is of course x, then it is thrown away,
oh and by the way, I have incremented x for you.
Extremely silly.)

Not sillier than your variant. The result of 'x += 1' is the old value
of 'x' plus 1 and it is thrown away in exactly the same way. The change
of the value of 'x' is nothing else than a side effect of 'x += 1' (yes,
it's like you said "oh and by the way, I have incremented x for you").

Keep in mind that the result of expression statement in C is _always_
thrown away. Any changes in values of objects involved in the expression
are _always_ caused by side effects. There's absolutely no difference
between 'x += 1' and 'x++' in this respect.
Now the above is using the side effect,
to mix up in one statement
new = x[ old ];
x[ old ] += 1;

It is *not* equivalent to
a = x[ a ] += 1;
because, being a post-increment, the original value of
x[ a ] must be used.


This is completely irrelevant. If you read this thread carefully, you'll
see that the real question is which value of 'a' is used (old or
new), not which value of 'x[a]' is used. The latter is pretty much
irrelevant.

The issue with 'a' is present in your version of the expression just
like it is present in the original version. You haven't changed anything
important by replacing post-increment with compound assignment.
This is valid, but is more appropriate for iocc than
supposedly maintainable code. There couldn't be a problem,
because there is nothing that is changed twice between the
sequence points, neither x[ old ] nor a .


"Changed twice"? It is not about changing anything twice and it's never
been. The rule in the standard consists of two parts. In short: 1) don't
change anything twice, 2) if you change some object, you can only read
the old value of that object to determine its new value. The discussion
here is centered around the second part of the rule. Nobody mentioned
the first one yet simply because it has noting to do with the expression
in question. The question is, once again, whether the original
expression violates the second part of the rule. This question applies
in exactly the same manner to your version. You haven't really changed
anything.
 
B

BRG

Albert said:
BRG said:
Does anyone here know whether the assignment:

a = x[ a ]++;

[snip]
This is valid, but is more appropriate for iocc than
supposedly maintainable code. There couldn't be a problem,
because there is nothing that is changed twice between the
sequence points, neither x[ old ] nor a .


Having had many good responses here, for which I am most grateful, my
own conclusion is that this statement produces an undefined result.

One relevant extract from the standard is:

"Between the previous and next sequence point an
object shall have its stored value modified at
most once by the evaluation of an expression.
Furthermore, the prior value shall be accessed
only to determine the value to be stored"

In the statement: k = x[ k ]++;

the value of k is modified once but its prior value is being used not
only to determine the new (stored) value but also to determine which
element in x[] is post-incremented. The latter use violates the last
sentence in the quoted paragraph.

Moreover, there appears to be nothing in the C standard to prevent
either of the interpretations:

t = k; k = x[t]; x[t]++;
or
k = x[k]; x[k]++;

each of which we know is implemenented in some compilers. And a
statement that can produce two different results has to produce
undefined behaviour as far as the C standard is concerned.
is legal in C and, if so, what array element in x[] is post incremented?
That is, does the old or the new value of a determine the index in
x[] of the post incremented array element.

I rather suspect the result is undefined - but am I right?


Because the optimiser got confused?


I checked this with the optimiser both on and off. I also checked the
assembler code being produced and it was quite evident that the
implementation of the second possible result above was deliberate.

Brian Gladman
 
A

Albert van der Horst

Albert said:
Does anyone here know whether the assignment:

a = x[ a ]++;


I never use a statement like
x++;
on its own.
Why?!

I always do the equivalent (barring the result value)
x += 1;
This shows that it is an assignment, rather than a side effect.


Rather poor reasoning since x++ is idiomatic, and because _all_
statements are _only_ evaluated for their side effects,
assignments or otherwise (e.g. function calls.)


You use side-effect in a politically correct way here.
I thought the context made clear that is not what I say.
In an expression like (i + j++)
two thing are happening with j, getting its value and the
incrementation which I call a side-effect. (And the use is
not improper, because it is indeed a lasting effect.).
Yes, ": @++ dup @ dup 1+ over ! ;" _is_ silly, but only because
Forth is silly. ;)

This leaves a pointer to x and has its value incremented.
It could be simplified to: @++ 1 over +! ;
It is not equivalent to the c-code x += 1;

Lets discuss @+ which leaves an incremented address
and a content, the equivalent of *p++ in c.

In the context of Forth it is indeed silly to
do
@+ DROP
instead of just
@
This is analogous. In the first example you calculate
two results, then throw one away. Instead of just calculating
a result.

But more on topic.
Is my
x += 1;
sufficiently un-idiomatic to get some eyes browsed?

What about
p += sizeof(struct x);
 
X

xarax

BRG said:
Albert said:
BRG said:
Does anyone here know whether the assignment:

a = x[ a ]++;

[snip]
This is valid, but is more appropriate for iocc than
supposedly maintainable code. There couldn't be a problem,
because there is nothing that is changed twice between the
sequence points, neither x[ old ] nor a .


Having had many good responses here, for which I am most grateful, my
own conclusion is that this statement produces an undefined result.

One relevant extract from the standard is:

"Between the previous and next sequence point an
object shall have its stored value modified at
most once by the evaluation of an expression.
Furthermore, the prior value shall be accessed
only to determine the value to be stored"

In the statement: k = x[ k ]++;

the value of k is modified once but its prior value is being used not
only to determine the new (stored) value but also to determine which
element in x[] is post-incremented. The latter use violates the last
sentence in the quoted paragraph.
No.

Moreover, there appears to be nothing in the C standard to prevent
either of the interpretations:

t = k; k = x[t]; x[t]++;


That is the correct implementation.
or
k = x[k]; x[k]++;

That is two accesses to the value at the memory
location named 'k' and one modification. The second
access occurs after the location is modified, which
is incorrect behavior (not undefined behavior).

There is nothing in the standard that allows the
compiler to re-evaluate the location of x[k] for
performing the post-increment.
each of which we know is implemenented in some compilers. And a
statement that can produce two different results has to produce
undefined behaviour as far as the C standard is concerned.

The compilers that generate the second implementation
are incorrect.
is legal in C and, if so, what array element in x[] is post incremented?
That is, does the old or the new value of a determine the index in
x[] of the post incremented array element.

I rather suspect the result is undefined - but am I right?


Because the optimiser got confused?


I checked this with the optimiser both on and off. I also checked the
assembler code being produced and it was quite evident that the
implementation of the second possible result above was deliberate.


Deliberately broken.
 
P

pete

Albert said:
Albert said:
a = x[ a ]++;

I never use a statement like
x++;
on its own.
Why?!

I always do the equivalent (barring the result value)
x += 1;
This shows that it is an assignment, rather than a side effect.


Rather poor reasoning since x++ is idiomatic, and because _all_
statements are _only_ evaluated for their side effects,
assignments or otherwise (e.g. function calls.)


You use side-effect in a politically correct way here.
I thought the context made clear that is not what I say.
In an expression like (i + j++)
two thing are happening with j, getting its value and the
incrementation which I call a side-effect. (And the use is
not improper, because it is indeed a lasting effect.).


"side effect" is a technical term in C.
This is a forum for discussing C.
 
K

Keith Thompson

Albert van der Horst said:
But more on topic.
Is my
x += 1;
sufficiently un-idiomatic to get some eyes browsed?

It's sufficiently un-idiomatic that my first thought on reading it
would be that the author hasn't yet learned about the ++ operator.
I'd only use it if it were part of a pattern, like:

x += 1;
y += 2;
z += 4;
What about
p += sizeof(struct x);

If p is a char*, it's fine. If p is a struct x*, it doesn't make much
sense.
 
T

Thomas Stegen

Keith said:
If p is a char*, it's fine. If p is a struct x*, it doesn't make much
sense.

Unless struct x is used to hold information about a byte and p is a
pointer to the first element of array an array of struct x's which are
storing information about struct x objects. Then the above
would take you to the struct x which holds information about the
first byte in the second struct x object.

I am not sure it makes sense in writing, but rest assured it does in
my head.
 
B

BRG

xarax said:
Having had many good responses here, for which I am most grateful, my
own conclusion is that this statement produces an undefined result.

One relevant extract from the standard is:

"Between the previous and next sequence point an
object shall have its stored value modified at
most once by the evaluation of an expression.
Furthermore, the prior value shall be accessed
only to determine the value to be stored"

In the statement: k = x[ k ]++;

the value of k is modified once but its prior value is being used not
only to determine the new (stored) value but also to determine which
element in x[] is post-incremented. The latter use violates the last
sentence in the quoted paragraph.

No.

The wording is quite clear. If k is modified then the _only_ purpose for
which the previous value of k can be accessed is in determining the new
value of k. Which means in this case that it cannot be legally accessed
to determine which element of x[] is to be post-incremented.
Moreover, there appears to be nothing in the C standard to prevent
either of the interpretations:

t = k; k = x[t]; x[t]++;

That is the correct implementation.
or
k = x[k]; x[k]++;

That is two accesses to the value at the memory
location named 'k' and one modification. The second
access occurs after the location is modified, which
is incorrect behavior (not undefined behavior).
There is nothing in the standard that allows the
compiler to re-evaluate the location of x[k] for
performing the post-increment.

The issue is whether there is anything in the standard that prevents
this interpretation.
each of which we know is implemenented in some compilers. And a
statement that can produce two different results has to produce
undefined behaviour as far as the C standard is concerned.

The compilers that generate the second implementation
are incorrect.
is legal in C and, if so, what array element in x[] is post incremented?
That is, does the old or the new value of a determine the index in
x[] of the post incremented array element.

I rather suspect the result is undefined - but am I right?

Because the optimiser got confused?


I checked this with the optimiser both on and off. I also checked the
assembler code being produced and it was quite evident that the
implementation of the second possible result above was deliberate.


Deliberately broken.


I believe you are wrong.

Brian Gladman
 

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,535
Members
45,007
Latest member
obedient dusk

Latest Threads

Top