Sequence Points, Aliasing & Optimisation 
Author Message
 Sequence Points, Aliasing & Optimisation


: OK, maybe this is a dumb question/FAQ (it's getting a little late) ...

(snip)

: if I compare that with, say:

: ...
: int i = 0;
: ...
: foobar(&i);
: ...
: if (i > 0) ...

: where foobar is:

: void foobar(int *n) {
:    *n = 1;
: }

: ... which appears to be a perfectly legitimate construct.  I mean, I'm
: still taking the address of a variable, and modifying it indirectly via
: the resulting pointer, but does the fact that a function call is
: executed change anything with respect to this?

: Thanks in advance for any thoughts on this ...

C is a sequential, procedural language. If you make a function call, the
calling function will patiently wait until the called function returns.
So there is nothing dangerous about the above bit of code, i will be 1
by the time your code gets to the line if (i > 0).

--

| Kingpriest of "The Flying Lemon Tree" G++ FR FW+ M- #80 D+ ADA N+++ |
| http://www.*-*-*.com/ ~palaste       W++ B OP+                     |
\----------------------------------------- Finland rules! ------------/

"Remember: There are only three kinds of people - those who can count and those
who can't."
   - Vampyra



Sat, 20 Jul 2002 03:00:00 GMT  
 Sequence Points, Aliasing & Optimisation


Quote:
>OK, maybe this is a dumb question/FAQ (it's getting a little late) ...

>Supposing I modify a variable via a pointer.  Then suppose I reference
>the original variable directly.  Assuming I didn't declare the variable
>itself as a volatile, are there any points at which I can rely on
>picking up the updated value, and not an earlier one stashed in a
>register?

The semantic of C are that values are held in objects. Updating an object
through a pointer is just as valid as through a variable name. The
All opdates to objects are complete by the next sequence point.

Quote:
>E.g:

>#include <stdlib.h>
>#include <stdio.h>

>int main(void) {

>int i = 0;
>int *p = &i;
>register int j;

>   *p = 1;
>   j = i;
>   *p = 2;
>   j += i;
>   fprintf(stdout,"j = %d\n",j);

>   return EXIT_SUCCESS;

>}

>I'm assuming (hopefully correctly) that the assignments to i via *p will
>be committed to memory by the next sequence point; that is, not cached
>in a register or optimised out.

When you write to *p the value of that object is changed. Any valid attempt
to read the value of that object after then next sequence point must get
the new value. Registers etc. are an implementation issue. However
whatever an implementation does it must preserve the semantics of the
language.

Quote:
> I guess what I'm concerned about is
>that it might conceivably assume that "i" hasn't been changed during
>execution, and do something "clever" such as assume a value of zero ...

A valid C compiler can't do that. The only time this is possible
is if i is modified by something other than the normal execution of
the program, e.g. in a signal handler. Other possibilities are threads,
shared memory, interrupts, hardware registers etc. but these are all
beyond standard C anyway.

- Show quoted text -

Quote:
>I've tried this on two compilers, and get j=3 in both cases, as would
>obviously be intended.  Is there any guarantee that I'll get the
>intended result, or is the above dangerous?  If it's safe, then the next
>question is probably moot, but ... if I compare that with, say:

>...
>int i = 0;
>...
>foobar(&i);
>...
>if (i > 0) ...

>where foobar is:

>void foobar(int *n) {
>   *n = 1;
>}

>... which appears to be a perfectly legitimate construct.  I mean, I'm
>still taking the address of a variable, and modifying it indirectly via
>the resulting pointer, but does the fact that a function call is
>executed change anything with respect to this?

No, it must still work. You should begin to see how using pointers
can in some cases seriously limit a compiler's optimisation options.

--
-----------------------------------------


-----------------------------------------



Sat, 20 Jul 2002 03:00:00 GMT  
 Sequence Points, Aliasing & Optimisation
OK, maybe this is a dumb question/FAQ (it's getting a little late) ...

Supposing I modify a variable via a pointer.  Then suppose I reference
the original variable directly.  Assuming I didn't declare the variable
itself as a volatile, are there any points at which I can rely on
picking up the updated value, and not an earlier one stashed in a
register?

E.g:

#include <stdlib.h>
#include <stdio.h>

int main(void) {

int i = 0;
int *p = &i;
register int j;

   *p = 1;
   j = i;
   *p = 2;
   j += i;
   fprintf(stdout,"j = %d\n",j);

   return EXIT_SUCCESS;

Quote:
}

I'm assuming (hopefully correctly) that the assignments to i via *p will
be committed to memory by the next sequence point; that is, not cached
in a register or optimised out.  I guess what I'm concerned about is
that it might conceivably assume that "i" hasn't been changed during
execution, and do something "clever" such as assume a value of zero ...

I've tried this on two compilers, and get j=3 in both cases, as would
obviously be intended.  Is there any guarantee that I'll get the
intended result, or is the above dangerous?  If it's safe, then the next
question is probably moot, but ... if I compare that with, say:

...
int i = 0;
...
foobar(&i);
...
if (i > 0) ...

where foobar is:

void foobar(int *n) {
   *n = 1;

Quote:
}

... which appears to be a perfectly legitimate construct.  I mean, I'm
still taking the address of a variable, and modifying it indirectly via
the resulting pointer, but does the fact that a function call is
executed change anything with respect to this?

Thanks in advance for any thoughts on this ...

-Ian.

--
Ian Stewart



Sun, 21 Jul 2002 03:00:00 GMT  
 Sequence Points, Aliasing & Optimisation
Thanks folks.  Yes, it must have been getting late.  It's slowly coming back
to me (I haven't done much C in the last year!)  I think I was getting
overly paranoid having stumbled across things like this previously:

#include <stdlib.h>
#include <stdio.h>
int main(void) {
int i = 0;
unsigned short *p = ((unsigned short *) &i) + 1;  /* big-endian machine */
register int j;
   *p = 1;
   j = i;
   *p = 2;
   j += i;
   fprintf(stdout,"j = %d\n",j);
   return EXIT_FAILURE;

Quote:
}

Oops.  OK, with this, one of my compilers gives me a warning that I may get
unexpected results!  With optimising turned on, it indeed does!  Its manual
includes a note under "common errors" that you can only assign to a variable
via a pointer using its own type, or a char *.

Quoting from the manual (which is quoting the C standard):  According to ISO
C, section 6.3 (Expressions):
    "An object shall have its stored value accessed only by an lvalue that
has one of the following types:
     -   the declared type of the object.
     -   a qualified version of the declared type of the object
     -   a type that is the signed or unsigned type corresponding to the
declared type of the object
     -   a type that is the signed or unsigned type corresponding to a
qualified version of the declared type of the object
     -   an aggregate or union type that includes one of the aforementioned
types among its members ... or
     -   a character type."

Interestingly enough if I mangle i via a char *, the warning goes away, and
the result is as might be expected!  Which tells me, among other things,
that I'm glad I'm not trying to write an optimiser!!

I guess that my clever macro to do direct assignment between fixed size
character arrays by trying to fool the compiler into thinking they're
structures is by this definition, invalid too ... never mind, a test using
memcpy took only slightly longer to move around 1M x 10 bytes, so I guess
there isn't much to be saved from that point of view.

Is this a normal part of the process of learning C?  I.e. from thinking
"this is easy ... through ... oops, there's more to this than I thought ...
through ... paranoia??!?

-Ian.

--
Ian Stewart



Sun, 21 Jul 2002 03:00:00 GMT  
 Sequence Points, Aliasing & Optimisation


Quote:
>Thanks folks.  Yes, it must have been getting late.  It's slowly coming back
>to me (I haven't done much C in the last year!)  I think I was getting
>overly paranoid having stumbled across things like this previously:

>#include <stdlib.h>
>#include <stdio.h>
>int main(void) {
>int i = 0;
>unsigned short *p = ((unsigned short *) &i) + 1;  /* big-endian machine */
>register int j;
>   *p = 1;
>   j = i;
>   *p = 2;
>   j += i;
>   fprintf(stdout,"j = %d\n",j);
>   return EXIT_FAILURE;
>}

>Oops.  OK, with this, one of my compilers gives me a warning that I may get
>unexpected results!  With optimising turned on, it indeed does!  Its manual
>includes a note under "common errors" that you can only assign to a variable
>via a pointer using its own type, or a char *.

Strictly that should be a pointer to any character type. However the
only truely portable type is a pointer to an unsigned char.

Quote:
>Quoting from the manual (which is quoting the C standard):  According to ISO
>C, section 6.3 (Expressions):
>    "An object shall have its stored value accessed only by an lvalue that
>has one of the following types:
>     -   the declared type of the object.
>     -   a qualified version of the declared type of the object
>     -   a type that is the signed or unsigned type corresponding to the
>declared type of the object
>     -   a type that is the signed or unsigned type corresponding to a
>qualified version of the declared type of the object
>     -   an aggregate or union type that includes one of the aforementioned
>types among its members ... or
>     -   a character type."

Correct.

Quote:
>Interestingly enough if I mangle i via a char *, the warning goes away, and
>the result is as might be expected!  Which tells me, among other things,
>that I'm glad I'm not trying to write an optimiser!!

This is itended to make optimisation easier. If your code trues to
access an int object through a short int lvalue the optimiser doesn't
have to worry about getting anything "right" because the code is
simply wrong.

Quote:
>I guess that my clever macro to do direct assignment between fixed size
>character arrays by trying to fool the compiler into thinking they're
>structures is by this definition, invalid too ... never mind, a test using
>memcpy took only slightly longer to move around 1M x 10 bytes, so I guess
>there isn't much to be saved from that point of view.

A good compiler should be able to inline memcpy to essentially the same
code as a direct object assignment would produce, assuming th assignment
was valid in the firt place.

Quote:
>Is this a normal part of the process of learning C?  I.e. from thinking
>"this is easy ... through ... oops, there's more to this than I thought ...
>through ... paranoia??!?

I don't know about paranoia but part of the learning process is certainly
debunking false assumptions.

--
-----------------------------------------


-----------------------------------------



Sun, 21 Jul 2002 03:00:00 GMT  
 
 [ 5 post ] 

 Relevant Pages 

1. Sequence Points & Side Effects

2. Assignment and sequence points

3. Sequence point question (function result semantics)

4. Sequence point or not?

5. Yet another sequence point question

6. Sequence points

7. sequence point in printf's argument list?

8. Sequence points in initializers

9. sequence points

10. Sequence points and undefined behaviour

11. Sequence points in this code

12. Sequence points

 

 
Powered by phpBB® Forum Software