[Coco] Found strangeness in C compiler (bug)

Joel Rees joel.rees at gmail.com
Fri May 24 19:05:55 EDT 2019


2019年5月21日(火) 14:32 Walter Zambotti <zambotti at iinet.net.au>:

> I have a situation where the auto post-increment was occurring first.


The increment only occurs at the wrong time when the pointer types are
> double (maybe float).  So the following code works for int but not double.
>
> int *da, *dN ; or double *da, *dN;
>
> *da++ = *dN++ * v - *da; // this is correct as the increment should happen

after the assignment.


Well, let's look at that from the pov of the compiler.

*da++ on the left means, literally, hold the current value of da for a
store reference (lvalue) and increment its value wherever its current
instance exists. The lvalue is effective at the point of the closest
assignment on the right. After that, the incremented value should become
the current value for reference, even if you haven't hit the first
semicolon on the right. (K&R said as much, if you understood how to read
it.)

If I analyze opinions to the contrary, some people who disagree with me
will disagree, so I'll just acknowledge that there are differences of
opinion. Some of those differences of opinions are held by optimizer
architects.

But, really, compact expressions may help focusing on the broader picture,
but they do fuzz over details like these. Best to be explicit and find
other ways of encapsulating the behavior, for instance. (Forth can often,
but by no means always, be more effective at something like this.)

*da++ = *dN++ * v - *da;
>
> *da = *dN * v - da*;
>
> The auto post increment on the left hand side of the "=" should occur after
> the assignment but it was occurring first.
>
> So I fixed the problem by converting the code to: (this code works for all)
>
> *da = *dN++ * v - *da; da++;  // this is correct by intention
>

This is not just correct by intention. It's probably the best way to
visually encapsulate the operation in any version of C, short of enclosing
it in a block like this:

{  *da = *dN++ * v - *da; da++;  }

(I'm not following what you're doing below, however. Was it code trying to
analyze what happened when?)

*da = *dN++ * v - *da; da++;
>
> *da = *dN * v - da*;
>
> Or (this code incorrectly works for doubles and correctly fails for ints)
>
> *da = *dN++ * v - *da++;  // this is wrong as the expression on the right
> increments da before it is assigns the value to where da points.
>

This is where the differences of opinion come into play.

By a strict reading (my strict reading, anyway) of K&R, the lvalue should
be set by the time the right side of the assignment is evaluated.
Optimizers that follow this often have to ignore some (apparent)
opportunities for optimization, so my strict reading is unpopular.

So, the standard says don't use side-effect expressions that potentially
conflict with each other on both sides of the assignment, and I have to
admit the standard is correct relative to the general industry (one issue
being that *da is often missed as being an expression with side effects).

I must admit, even though I don't use comma expressions much (except in
loop control expressions, where they can do the most damage if
misunderstood, so I've been giving that up, too), playing with comma
expressions can be useful in understanding how to read an expression like a
compiler.

*da = *dN++ * v - *da++;
>
> *da = *dN * v - da*;
>
>
>
> Ensuring the increment occurred last in order to get it working.
>
>
>
> However when I can't duplicate the problem in an isolated example.
>
>
>
> Do we have the C source anywhere?
>
>
>
> Walter
>
>
> --
> Coco mailing list
> Coco at maltedmedia.com
> https://pairlist5.pair.net/mailman/listinfo/coco
>


More information about the Coco mailing list