Sequence point question (function result semantics) 
Author Message
 Sequence point question (function result semantics)

Hello,

I got a question about a statement in the C99 standard (and possibly
previous ones as well) about an undefined behaviour in J.2. The
statement is:
        An attempt is made to modify the result of a function call, a
        conditional operator, an assignment operator, or a comma
        operator, or to access it after the next sequence point
        (6.5.2.2, 6.5.15, 6.5.16, 6.5.17).
for those of you whom don't want to look it up. I understand the
majority of this statement. However, if I am reading it correctly then
code like
        int foo (void);

        void
        bar (void)
        {
                int c;
                c = (foo())++;
        }
results in undefined behaviour due to the attempt to modify the result
of the function call to ``foo''? I personally abhor code like this, but
I have seen such things done. Is this truly undefined?

If it is, are statements like:
        struct tm* foo (void);

        void
        bar (void)
        {
                int min;

                min = foo()->tm_min;
        }
undefined as well?

I understand the nastiness hidden in these examples, but they are only
some contrived examples.

Thanks.
------------------------------------------------------------------------
Dave Shawley                                  Embedded Software Engineer

"More computing sins are committed in the name of efficiency (without
 necessarily achieving it) that for any other single reason -- including
 blind stupidity." -- W.A. Wulf
------------------------------------------------------------------------
--
--



Thu, 26 Jun 2003 12:47:53 GMT  
 Sequence point question (function result semantics)


Quote:
>       int foo (void);

>       void
>       bar (void)
>       {
>               int c;
>               c = (foo())++;
>       }
>results in undefined behaviour due to the attempt to modify the result
>of the function call to ``foo''? I personally abhor code like this, but
>I have seen such things done. Is this truly undefined?

Yes, you have applied ++ to an rvalue. Of course many compilers will do
what you want, but that is the nature of undefined behaviour.

Quote:

>If it is, are statements like:
>       struct tm* foo (void);

>       void
>       bar (void)
>       {
>               int min;

>               min = foo()->tm_min;
>       }
>undefined as well?

You mean assuming that foo returns an address? Not the same as the
previous example, and seems to be perfectly OK. You are not modifying
the return value, but using it to access something.

Quote:

>I understand the nastiness hidden in these examples, but they are only
>some contrived examples.

Francis Glassborow      Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
--



Sun, 29 Jun 2003 12:38:36 GMT  
 Sequence point question (function result semantics)

Quote:

> I got a question about a statement in the C99 standard (and possibly
> previous ones as well) about an undefined behaviour in J.2. The
> statement is:
>         An attempt is made to modify the result of a function call, a
>         conditional operator, an assignment operator, or a comma
>         operator, or to access it after the next sequence point
>         (6.5.2.2, 6.5.15, 6.5.16, 6.5.17).
> for those of you whom don't want to look it up. I understand the
> majority of this statement. However, if I am reading it correctly then
> code like
>         int foo (void);

>         void
>         bar (void)
>         {
>                 int c;
>                 c = (foo())++;
>         }
> results in undefined behaviour due to the attempt to modify the result
> of the function call to ``foo''? I personally abhor code like this, but
> I have seen such things done. Is this truly undefined?

It has to be.  One implementation example should suffice -
functions return results in the accumulator acc, including foo.
(foo()) alone returns a value in acc, which is to be stored in c.
The store process involves flipping acc with a stack value. Now
where is the (foo()) to be incremented for future use?  There is
no future use, there is no storage location, etc.

Quote:
> If it is, are statements like:
>         struct tm* foo (void);

>         void
>         bar (void)
>         {
>                 int min;

>                 min = foo()->tm_min;
>         }
> undefined as well?

I see nothing wrong with this.  foo evaluates to a pointer to a
structure whose tm_min field is to be accessed.

Quote:
> I understand the nastiness hidden in these examples, but they are only
> some contrived examples.

--


http://www.qwikpages.com/backstreets/cbfalconer
   (Remove "NOSPAM." from reply address. my-deja works unmodified)

--



Sun, 29 Jun 2003 12:38:45 GMT  
 Sequence point question (function result semantics)


Quote:
>Hello,

>I got a question about a statement in the C99 standard (and possibly
>previous ones as well) about an undefined behaviour in J.2. The
>statement is:
>    An attempt is made to modify the result of a function call, a
>    conditional operator, an assignment operator, or a comma
>    operator, or to access it after the next sequence point
>    (6.5.2.2, 6.5.15, 6.5.16, 6.5.17).
>for those of you whom don't want to look it up. I understand the
>majority of this statement. However, if I am reading it correctly then
>code like
>    int foo (void);

>    void
>    bar (void)
>    {
>            int c;
>            c = (foo())++;
>    }

This looks undefined. The register that hold the return for foo()
may be read only.

Quote:
>results in undefined behaviour due to the attempt to modify the result
>of the function call to ``foo''? I personally abhor code like this, but
>I have seen such things done. Is this truly undefined?

>If it is, are statements like:
>    struct tm* foo (void);

>    void
>    bar (void)
>    {
>            int min;

>            min = foo()->tm_min;
>    }
>undefined as well?

This doesn't modify the result of the function foo(). This should be
fine.

Quote:
>I understand the nastiness hidden in these examples, but they are only
>some contrived examples.

>Thanks.
>------------------------------------------------------------------------
>Dave Shawley                                  Embedded Software Engineer

>"More computing sins are committed in the name of efficiency (without
> necessarily achieving it) that for any other single reason -- including
> blind stupidity." -- W.A. Wulf
>------------------------------------------------------------------------
>--
>--


 http://shaun.tancheff.com/       /?/                 -_-

--



Sun, 29 Jun 2003 12:42:35 GMT  
 Sequence point question (function result semantics)
Hi Dave,

I think that it is about the separation of a register
value and an lvalue. In general, I just assume that the
return value of a function will be presented in a
physical register to the caller - you can only have
integral types in there, but an int-register could
even be modified. Well, C99 does not want to have
a return value to be an lvalue - AFAICS it is about
the new feature of struct-returns which are not just
integral types, instead the struct-return is allocated
temporarily. It's no good to see such a temporary as
an lvalue. As an example, I refer to 6.5.3.2 #6

       [#6] EXAMPLE 1 If f is a function returning a  structure  or
       union,  and  x is a member of that structure or union, f().x
       is a valid postfix expression but is not an lvalue.

In your example, your first definition of foo and
the use of "++" is invalid since "++" assigns to
a temporary. The change is atleast lost.... unless
the final c has not been assiged the same cpu register
because the compiler was allowed to assume that he
could just do that aliasing...

Quote:

>         int foo (void);

>         void
>         bar (void)
>         {
>                 int c;
>                 c = (foo())++;
>         }

Your second example however did not assign to the return value,
it just used it as pointer that did fetch from something not
a temporary space of the function-call itself.
Quote:
>                min = foo()->tm_min;

so this is just correct.

Therefore:
Just assume that the lifespan of a return value ends at the
next sequence point, it may be possible to change something,
but it is ambigous, if the change will survive the next sequence
point because the compiler has *aliased* the return temporary
with the final storage. This is of extra importance to structures
since the called function will mostly get an invisible pointer
that it should place the result in. This result-area may be
a temporary but an optimizer is allowed to pass the address of
the final storage - the compiler is just allowed to do so,
*because* of the section you quoted.

Please, everyone, correct me if I got that wrong....

-- guido                                Edel sei der Mensch, hilfreich und gut

--



Sun, 29 Jun 2003 12:38:25 GMT  
 Sequence point question (function result semantics)

Quote:



> >       int foo (void);

> >       void
> >       bar (void)
> >       {
> >               int c;
> >               c = (foo())++;
> >       }
> >results in undefined behaviour due to the attempt to modify the result
> >of the function call to ``foo''? I personally abhor code like this, but
> >I have seen such things done. Is this truly undefined?

> Yes, you have applied ++ to an rvalue. Of course many compilers will do
> what you want, but that is the nature of undefined behaviour.

But what is the difference between this and "static int x; c = (x+1)++;" ?

If course it cannot be done, because x+1 is an rvalue, but there is no
undefined behavior whatsovever, it is just a violation of the language
rules that the compiler has to notice and refuse to compile. c =
(foo())++; should be the same, just illegal code, but not undefined
behavior.
--



Mon, 30 Jun 2003 01:28:52 GMT  
 Sequence point question (function result semantics)
On 10 Jan 2001 04:38:36 GMT, Francis Glassborow

Quote:

>>If it is, are statements like:
>>       struct tm* foo (void);

>>       void
>>       bar (void)
>>       {
>>               int min;

>>               min = foo()->tm_min;
>>       }
>>undefined as well?
>You mean assuming that foo returns an address? Not the same as the
>previous example, and seems to be perfectly OK. You are not modifying
>the return value, but using it to access something.

Except that

        foo()->tm_min        = min;

is proscribed.

--
#include <standard.disclaimer>
 _
Kevin D Quitt  USA 91351-4454           96.37% of all statistics are made up
Per the FCA, this email address may not be added to any commercial mail list
--



Mon, 30 Jun 2003 13:33:35 GMT  
 Sequence point question (function result semantics)


Quote:
>On 10 Jan 2001 04:38:36 GMT, Francis Glassborow

>>>If it is, are statements like:
>>>       struct tm* foo (void);

>>>       void
>>>       bar (void)
>>>       {
>>>               int min;

>>>               min = foo()->tm_min;
>>>       }
>>>undefined as well?
>>You mean assuming that foo returns an address? Not the same as the
>>previous example, and seems to be perfectly OK. You are not modifying
>>the return value, but using it to access something.

>Except that

>    foo()->tm_min        = min;

>is proscribed.

Is it?  I can see where

   foo().tm_min = min;

would be.  But I see no fundamental differentce between

   foo()->tm_min = min;

and

   a_min[foo()] = min;

or even

   p = foo();
   p->tm_min = min;

Regards,

Icarus
--
"Where there is no fear, there can be no courage"

--



Tue, 01 Jul 2003 09:33:44 GMT  
 Sequence point question (function result semantics)

Quote:

> But what is the difference between this and "static int x; c = (x+1)++;" ?

> If course it cannot be done, because x+1 is an rvalue, but there is no
> undefined behavior whatsovever, it is just a violation of the language
> rules that the compiler has to notice and refuse to compile.

No, it doesn't; it has to notice it and emit a diagnostic, but it is
free to continue compiling. If it does, though, and it produces an
executable from this code, the behaviour of that is undefined.

Richard
--



Wed, 02 Jul 2003 01:35:59 GMT  
 Sequence point question (function result semantics)

Quote:

> I understand the
> majority of this statement. However, if I am reading it correctly then
> code like
>         int foo (void);

>         void
>         bar (void)
>         {
>                 int c;
>                 c = (foo())++;
>         }
> results in undefined behaviour due to the attempt to modify the result
> of the function call to ``foo''? I personally abhor code like this, but
> I have seen such things done. Is this truly undefined?

  Having read the answers given, I'm a bit confused.  AFAIK, the
post-fix
operator++ has lower precedence than the operator=.  Thus c should be
assigned
the value of foo() and....  Well that value is incremented but ignored.

  I would think it would be analagous to:

  int y;
  const int x = 8;

  y = x;
  x++;

where y gets the value 8 and the compiler screams like the{*filter*}ens
that you tried to increment a const.  Except in this case foo()
disappears
after being incremented and I would only expect a warning from the
compiler.
If someone can clearly explain why c doesn't or may or may not get the
value
of foo(), and why anyone would care that the return value is incremented
and
discarded I would appreciate it.  Just repeating that it is undefined
behaviour explains nothing and does not enlighten the uninitiated.

BTW, I probably would have posted the question to comp.std.c instead,
where
the truly picky linguists hang out.

--Jeff Turner
--



Sun, 06 Jul 2003 04:03:01 GMT  
 Sequence point question (function result semantics)


Quote:

>> I understand the
>> majority of this statement. However, if I am reading it correctly then
>> code like
>>         int foo (void);

>>         void
>>         bar (void)
>>         {
>>                 int c;
>>                 c = (foo())++;
>>         }
[...]
>  Having read the answers given, I'm a bit confused.  AFAIK, the
>post-fix
>operator++ has lower precedence than the operator=.  Thus c should be
>assigned
>the value of foo() and....  Well that value is incremented but ignored.
[...]
>BTW, I probably would have posted the question to comp.std.c instead,
>where
>the truly picky linguists hang out.

And the truly picky linguists would point out that the first (and
only) listed constraint for postfix increment and decrement operators
(6.5.2.4p1 in n869) states "The operand of the postfix increment or
decrement operator shall have qualified or unqualified real or pointer
type and shall be a modifiable lvalue."

"foo()" in the above code is not a modifiable lvalue.  

"Constraints" BTW, are (according to the standard) "restrictions, both
syntactic and semantic, by which the exposition of language elements
is to be interpreted."  If a constraint is violated, a diagnostic
message must be produced.

The prefix increment and decrement operators (6.5.3.1) have the same
constraint.

Regards,

Icarus
--
"Where there is no fear, there can be no courage"

--



Tue, 08 Jul 2003 10:49:20 GMT  
 Sequence point question (function result semantics)

Quote:




> >> I understand the
> >> majority of this statement. However, if I am reading it correctly then
> >> code like
> >>         int foo (void);

> >>         void
> >>         bar (void)
> >>         {
> >>                 int c;
> >>                 c = (foo())++;
> >>         }
> [...]
> >  Having read the answers given, I'm a bit confused.  AFAIK, the
> >post-fix
> >operator++ has lower precedence than the operator=.  Thus c should be
> >assigned
> >the value of foo() and....  Well that value is incremented but ignored.
> [...]
> >BTW, I probably would have posted the question to comp.std.c instead,
> >where
> >the truly picky linguists hang out.

> And the truly picky linguists would point out that the first (and
> only) listed constraint for postfix increment and decrement operators
> (6.5.2.4p1 in n869) states "The operand of the postfix increment or
> decrement operator shall have qualified or unqualified real or pointer
> type and shall be a modifiable lvalue."

> "foo()" in the above code is not a modifiable lvalue.

> "Constraints" BTW, are (according to the standard) "restrictions, both
> syntactic and semantic, by which the exposition of language elements
> is to be interpreted."  If a constraint is violated, a diagnostic
> message must be produced.

> The prefix increment and decrement operators (6.5.3.1) have the same
> constraint.

> Regards,

> Icarus

Thanks for the "Standards Requirement".  I'm not knowledgeable enough to
question that a diagnostic must be produced.  But as a programmer in the
real world, if the proper value was placed in c, I'd just redirect the
diagnostic to /dev/null.  The only pertinent question to me is does c
get
the value I expect it to?

--Jeff Turner
--



Fri, 11 Jul 2003 12:30:36 GMT  
 Sequence point question (function result semantics)


Quote:
>Thanks for the "Standards Requirement".  I'm not knowledgeable enough to
>question that a diagnostic must be produced.  But as a programmer in the
>real world, if the proper value was placed in c, I'd just redirect the
>diagnostic to /dev/null.  The only pertinent question to me is does c
>get
>the value I expect it to?

And I think the answer to that is that it all depends on what you expect
and which compiler you are using.

Francis Glassborow      Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
--



Sat, 12 Jul 2003 02:38:32 GMT  
 Sequence point question (function result semantics)

Quote:



> >Thanks for the "Standards Requirement".  I'm not knowledgeable enough to
> >question that a diagnostic must be produced.  But as a programmer in the
> >real world, if the proper value was placed in c, I'd just redirect the
> >diagnostic to /dev/null.  The only pertinent question to me is does c
> >get
> >the value I expect it to?

> And I think the answer to that is that it all depends on what you expect
> and which compiler you are using.

Well, the obvious answer to what I'd expect from:

c = (f(x))++;

is what it _looks_ like it should put in c, namely, f(x).  I'm not
concerned
with what happens to f(x) after that.  I don't understand why this
should be
compiler dependent.  The postfix operator++ always increments after
assignment.

I expect it to be analagous to:

c = x++;

which I trust is NOT compiler dependent.

Yours,

Jeff Turner
--



Sun, 13 Jul 2003 08:01:43 GMT  
 Sequence point question (function result semantics)


Quote:

>> I understand the
>> majority of this statement. However, if I am reading it correctly then
>> code like
>>         int foo (void);

>>         void
>>         bar (void)
>>         {
>>                 int c;
>>                 c = (foo())++;
>>         }
>> results in undefined behaviour due to the attempt to modify the result
>> of the function call to ``foo''? I personally abhor code like this, but
>> I have seen such things done. Is this truly undefined?

>  Having read the answers given, I'm a bit confused.  AFAIK, the
>post-fix
>operator++ has lower precedence than the operator=.  Thus c should be
>assigned
>the value of foo() and....  Well that value is incremented but ignored.

Precedence is suffix, prefix, infix operators!
Arithmetic and logical operators are where you'd expect them to
be: all other combinations should be parenthesized to avoid
surprises.
Conditional operator is higher than assignment operators, which
are just above the comma operator, at the very bottom of the
precedence list!
Also, only prefix, conditional, assignment operators group right
to left, rest group left to right.
Here endeth the lesson -- it's Sunday! ;^>

- Show quoted text -

Quote:
>  I would think it would be analagous to:

>  int y;
>  const int x = 8;

>  y = x;
>  x++;

>where y gets the value 8 and the compiler screams like the{*filter*}ens
>that you tried to increment a const.  Except in this case foo()
>disappears
>after being incremented and I would only expect a warning from the
>compiler.
>If someone can clearly explain why c doesn't or may or may not get the
>value
>of foo(), and why anyone would care that the return value is incremented
>and
>discarded I would appreciate it.  Just repeating that it is undefined
>behaviour explains nothing and does not enlighten the uninitiated.

>BTW, I probably would have posted the question to comp.std.c instead,
>where
>the truly picky linguists hang out.

>--Jeff Turner

Thanks. Take care, Brian Inglis         Calgary, Alberta, Canada
--

                                use address above to reply
--



Sun, 13 Jul 2003 08:20:51 GMT  
 
 [ 38 post ]  Go to page: [1] [2] [3]

 Relevant Pages 

1. Yet another sequence point question

2. Floating-point semantics in C

3. function calculates correctly, but the result of each succession is added to the previos result

4. Assignment and sequence points

5. Sequence Points & Side Effects

6. Sequence point or not?

7. Sequence points

8. sequence point in printf's argument list?

9. Sequence points in initializers

10. Sequence Points, Aliasing & Optimisation

11. sequence points

12. Sequence points and undefined behaviour

 

 
Powered by phpBB® Forum Software