C Quiz

Discussion in 'C Programming' started by flameice9, Jun 18, 2010.

  1. flameice9

    flameice9 Guest

    Does the following program invoke undefined behaviour?

    int x;
    int f(void) {
    x = 1;
    return 2;
    }
    int main(void) {
    x = f();
    }
     
    flameice9, Jun 18, 2010
    #1
    1. Advertising

  2. flameice9

    Ian Collins Guest

    On 06/18/10 09:28 PM, flameice9 wrote:
    > Does the following program invoke undefined behaviour?
    >
    > int x;
    > int f(void) {
    > x = 1;
    > return 2;
    > }
    > int main(void) {
    > x = f();
    > }


    No.

    --
    Ian Collins
     
    Ian Collins, Jun 18, 2010
    #2
    1. Advertising

  3. Il 18/06/2010 11:28, flameice9 ha scritto:
    > Does the following program invoke undefined behaviour?
    >
    > int x;
    > int f(void) {
    > x = 1;
    > return 2;
    > }
    > int main(void) {
    > x = f();
    > }


    Its behaviour is pretty well-defined:

    1) x==0 before calling f
    2) x==1 before returning from f
    3) x==2 before returning(?) from main

    --
    Vincenzo Mercuri
     
    Vincenzo Mercuri, Jun 18, 2010
    #3
  4. Le 18/06/2010 11:28, flameice9 a écrit :
    > Does the following program invoke undefined behaviour?
    >
    > int x;
    > int f(void) {
    > x = 1;
    > return 2;
    > }
    > int main(void) {
    > x = f();
    > }


    No. However, in a hosted environment, the termination status returned to
    the host environment is unspecified.
    To fix this, before the last } in main() add this line:
    return 0;

    Francois Grieu
     
    Francois Grieu, Jun 18, 2010
    #4
  5. flameice9

    flameice9 Guest

    On Jun 18, 4:31 am, Ian Collins <> wrote:
    > On 06/18/10 09:28 PM, flameice9 wrote:
    >
    > > Does the following program invoke undefined behaviour?

    >
    > > int x;
    > > int f(void) {
    > >    x = 1;
    > >    return 2;
    > > }
    > > int main(void) {
    > >    x = f();
    > > }

    >
    > No.


    The standard says only that the updating of the stored value of the
    left
    operand of the = operator is performed between the previous and next
    sequence point. What stops an implementation from noticing f always
    returns 2 and deciding to perform this update prior to the call to f?
    Worse, what stops an implementation from deciding to perform this
    update
    "at the same time" as the x = 1 expression inside f, thus modifying x
    twice between sequence points?
     
    flameice9, Jun 18, 2010
    #5
  6. On Fri, 18 Jun 2010, flameice9 wrote:

    > On Jun 18, 4:31 am, Ian Collins <> wrote:
    >> On 06/18/10 09:28 PM, flameice9 wrote:
    >>
    >>> Does the following program invoke undefined behaviour?

    >>
    >>> int x;
    >>> int f(void) {
    >>>    x = 1;
    >>>    return 2;
    >>> }
    >>> int main(void) {
    >>>    x = f();
    >>> }

    >>
    >> No.

    >
    > The standard says only that the updating of the stored value of the left
    > operand of the = operator is performed between the previous and next
    > sequence point. What stops an implementation from noticing f always
    > returns 2 and deciding to perform this update prior to the call to f?
    > Worse, what stops an implementation from deciding to perform this update
    > "at the same time" as the x = 1 expression inside f, thus modifying x
    > twice between sequence points?


    An implementation must comply with the workings of the abstract machine.

    In main(), x can't be assigned to until f() is evaluated (= until f()
    returns). When f() returns, the "x = 1" assignment is complete. (There is
    a sequence point after that expression in f().) In main(), you need the
    value returned by f() to evaluate the assignment operator. At that time,
    "x = 1" is already complete.

    Somewhat related:

    http://www.open-std.org/Jtc1/sc22/wg14/www/docs/dr_087.html

    lacos
     
    Ersek, Laszlo, Jun 18, 2010
    #6
  7. Francois Grieu wrote:

    > Le 18/06/2010 11:28, flameice9 a écrit :
    >> Does the following program invoke undefined behaviour?
    >>
    >> int x;
    >> int f(void) {
    >> x = 1;
    >> return 2;
    >> }
    >> int main(void) {
    >> x = f();
    >> }

    >
    > No. However, in a hosted environment, the termination status returned to
    > the host environment is unspecified.
    > To fix this, before the last } in main() add this line:
    > return 0;
    >
    > Francois Grieu


    C99 5.1.2.2.3: "... reaching the } that terminates the main function returns
    a value of 0."

    (I have only the N1256 draft, though)
     
    Alexander Klauer, Jun 18, 2010
    #7
  8. flameice9

    Richard Bos Guest

    flameice9 <> wrote:

    > On Jun 18, 4:31=A0am, Ian Collins <> wrote:
    > > On 06/18/10 09:28 PM, flameice9 wrote:
    > >
    > > > Does the following program invoke undefined behaviour?


    [ I've rearranged it slightly for legibility; no behaviour changes. ]

    > > > int x;
    > > >
    > > > int f(void)
    > > > {
    > > > x = 1;
    > > > return 2;
    > > > }
    > > >
    > > > int main(void)
    > > > {
    > > > x = f();
    > > > }

    > >
    > > No.

    >
    > The standard says only that the updating of the stored value of the left
    > operand of the = operator is performed between the previous and next
    > sequence point. What stops an implementation from noticing f always
    > returns 2 and deciding to perform this update prior to the call to f?


    The sequence points. There's one just before the call to f(), and one
    just after each statement inside f().

    Richard
     
    Richard Bos, Jun 18, 2010
    #8
  9. Francois Grieu <> writes:

    > Le 18/06/2010 11:28, flameice9 a écrit :
    >> Does the following program invoke undefined behaviour?
    >>
    >> int x;
    >> int f(void) {
    >> x = 1;
    >> return 2;
    >> }
    >> int main(void) {
    >> x = f();
    >> }

    >
    > No. However, in a hosted environment, the termination status returned to
    > the host environment is unspecified.


    Not in C99. Omitting the return is permitted.

    > To fix this, before the last } in main() add this line:
    > return 0;


    That's the effect, in C99, of leaving out the return.

    --
    Ben.
     
    Ben Bacarisse, Jun 18, 2010
    #9
  10. flameice9

    flameice9 Guest

    On Jun 18, 6:04 am, "Ersek, Laszlo" <> wrote:
    > On Fri, 18 Jun 2010, flameice9 wrote:
    >> On Jun 18, 4:31 am, Ian Collins <> wrote:
    >>> On 06/18/10 09:28 PM, flameice9 wrote:

    >
    >>>> Does the following program invoke undefined behaviour?

    >
    >>>> int x;
    >>>> int f(void) {
    >>>> x = 1;
    >>>> return 2;
    >>>> }
    >>>> int main(void) {
    >>>> x = f();
    >>>> }

    >
    >>> No.

    >
    >> The standard says only that the updating of the stored value of the left
    >> operand of the = operator is performed between the previous and next
    >> sequence point. What stops an implementation from noticing f always
    >> returns 2 and deciding to perform this update prior to the call to f?
    >> Worse, what stops an implementation from deciding to perform this update
    >> "at the same time" as the x = 1 expression inside f, thus modifying x
    >> twice between sequence points?

    >
    > An implementation must comply with the workings of the abstract machine.
    >
    > In main(), x can't be assigned to until f() is evaluated (= until f()
    > returns).


    This makes sense intuitively, but there appears to be nothing
    requiring a function call to be evaluated prior to its returned value
    being used. Of course, this is possible only for functions for which
    the returned value can be deduced prior to the call.
     
    flameice9, Jun 18, 2010
    #10
  11. Il 18/06/2010 12:34, Francois Grieu ha scritto:
    > Le 18/06/2010 11:28, flameice9 a écrit :
    >> Does the following program invoke undefined behaviour?
    >>
    >> int x;
    >> int f(void) {
    >> x = 1;
    >> return 2;
    >> }
    >> int main(void) {
    >> x = f();
    >> }

    >
    > No. However, in a hosted environment, the termination status returned to
    > the host environment is unspecified.
    > To fix this, before the last } in main() add this line:
    > return 0;
    >
    > Francois Grieu


    Actually before C99 the value returned by main would be undefined.
    So, althought the program compiles and the variable x has the expected
    values, it's undefined how the operating system would handle that
    process (because of it's undefined exit status).

    --
    Vincenzo Mercuri
     
    Vincenzo Mercuri, Jun 18, 2010
    #11
  12. flameice9

    flameice9 Guest

    On Jun 18, 6:26 am, (Richard Bos) wrote:
    > flameice9 <> wrote:
    >> On Jun 18, 4:31=A0am, Ian Collins <> wrote:
    >>> On 06/18/10 09:28 PM, flameice9 wrote:
    >>>> Does the following program invoke undefined behaviour?
    >>>> int x;
    >>>>
    >>>> int f(void)
    >>>> {
    >>>> x = 1;
    >>>> return 2;
    >>>> }
    >>>>
    >>>> int main(void)
    >>>> {
    >>>> x = f();
    >>>> }
    >>>
    >>> No.

    >>
    >> The standard says only that the updating of the stored value of the left
    >> operand of the = operator is performed between the previous and next
    >> sequence point. What stops an implementation from noticing f always
    >> returns 2 and deciding to perform this update prior to the call to f?

    >
    > The sequence points. There's one just before the call to f(), and one
    > just after each statement inside f().


    Indeed, execution proceeds as follows:

    <sequence point A> (implicit at program start)
    <sequence point> (just before f is called)
    x = 1
    <sequence point B> ("x = 1;" completes)
    return 2
    <sequence point> (the return statement completes)
    <sequence point C> ("x = f();" completes)

    However, 6.5.16p3 says only that, in "x = f();", the side effect of
    updating the value of x shall occur at some time between A and C. I
    cannot determine why it must be done after B.
     
    flameice9, Jun 18, 2010
    #12
  13. flameice9

    flameice9 Guest

    On Jun 18, 7:25 am, pete <> wrote:
    > flameice9 wrote:
    > > This makes sense intuitively, but there appears to be nothing
    > > requiring a function call to be evaluated prior to its returned value
    > > being used. Of course, this is possible only for functions for which
    > > the returned value can be deduced prior to the call.

    >
    > Being able to deduce the return value
    > without the function call actually being made,
    > only allows the program to omit the function call
    > if the program has the same behavior
    > as it would if the function call were actually made.


    Where is it stated or implied in the standard that in a function call
    expression, the call occurs prior to the value of the expression being
    used?
     
    flameice9, Jun 18, 2010
    #13
  14. flameice9

    flameice9 Guest

    On Jun 18, 4:28 pm, Richard Heathfield <> wrote:
    > flameice9 wrote:
    >> Where is it stated or implied in the standard that in a function call
    >> expression, the call occurs prior to the value of the expression being
    >> used?

    >
    > Where it says that there is a sequence point before the function call.
    >
    > At this point, where the function is about to be called but has not yet
    > been called, the fact that the function has not yet been called means
    > that its return value is not available (in the abstract machine).


    Right, there is a sequence point just before the call. But I see
    nothing in the standard requiring the sequence point and call to
    occur prior to the return value being known and used. I agree that it
    does not make intuitive sense for the return value to be known and
    used before the call occurs. However, given my example program:

    int x;
    int f(void) {
    x = 1;
    return 2;
    }
    int main(void) {
    x = f();
    }

    consider an implementation that notices both that f always returns
    and that f always returns 2. If the implementation decides to
    evaluate "x = f();" by first setting x to 2, then calling f (to
    perform f's side effect), what part of the standard has been
    violated? I agree that this is not how the abstract machine is
    intended to behave, but this intent is not expressed in the standard.
     
    flameice9, Jun 19, 2010
    #14
  15. flameice9

    Ian Collins Guest

    On 06/19/10 11:44 AM, flameice9 wrote:
    > On Jun 18, 4:28 pm, Richard Heathfield<> wrote:
    >> flameice9 wrote:
    >>> Where is it stated or implied in the standard that in a function call
    >>> expression, the call occurs prior to the value of the expression being
    >>> used?

    >>
    >> Where it says that there is a sequence point before the function call.
    >>
    >> At this point, where the function is about to be called but has not yet
    >> been called, the fact that the function has not yet been called means
    >> that its return value is not available (in the abstract machine).

    >
    > Right, there is a sequence point just before the call. But I see
    > nothing in the standard requiring the sequence point and call to
    > occur prior to the return value being known and used. I agree that it
    > does not make intuitive sense for the return value to be known and
    > used before the call occurs. However, given my example program:
    >
    > int x;
    > int f(void) {
    > x = 1;
    > return 2;
    > }
    > int main(void) {
    > x = f();
    > }
    >
    > consider an implementation that notices both that f always returns
    > and that f always returns 2. If the implementation decides to
    > evaluate "x = f();" by first setting x to 2, then calling f (to
    > perform f's side effect), what part of the standard has been
    > violated? I agree that this is not how the abstract machine is
    > intended to behave, but this intent is not expressed in the standard.


    None, the value of f() still has to be assigned to x.

    If the compiler knows f always returns 2, it will also know that f
    doesn't have any side effects and it is free to set x to 2 and not call
    f. Which is the same as inlining f.

    --
    Ian Collins
     
    Ian Collins, Jun 19, 2010
    #15
  16. flameice9

    flameice9 Guest

    On Jun 19, 6:07 am, Ian Collins <> wrote:
    > On 06/19/10 11:44 AM, flameice9 wrote:
    >> int x;
    >> int f(void) {
    >> x = 1;
    >> return 2;
    >> }
    >> int main(void) {
    >> x = f();
    >> }

    >
    >> consider an implementation that notices both that f always returns
    >> and that f always returns 2. If the implementation decides to
    >> evaluate "x = f();" by first setting x to 2, then calling f (to
    >> perform f's side effect), what part of the standard has been
    >> violated? I agree that this is not how the abstract machine is
    >> intended to behave, but this intent is not expressed in the standard.

    >
    > None, the value of f() still has to be assigned to x.


    Yes, but this occurs at an unspecified time between the sequence
    point just before x = f() and the sequence point just after it (see
    the last sentence of C99 6.5.16p3). Nothing requires x to have the
    value of f() after x = f(); is complete. It is allowable that the
    x = 1 assignment is performed after the x = f() assignment.
     
    flameice9, Jun 19, 2010
    #16
  17. flameice9 <> writes:

    > On Jun 19, 6:07 am, Ian Collins <> wrote:
    >> On 06/19/10 11:44 AM, flameice9 wrote:


    <example snipped because I reproduce it below>

    >> None, the value of f() still has to be assigned to x.

    >
    > Yes, but this occurs at an unspecified time between the sequence
    > point just before x = f() and the sequence point just after it (see
    > the last sentence of C99 6.5.16p3). Nothing requires x to have the
    > value of f() after x = f(); is complete. It is allowable that the
    > x = 1 assignment is performed after the x = f() assignment.


    How do you arrive at that conclusion?

    That is a genuine question and there seem to be two possibilities: (a)
    you feel that some aspects of the language are under-specified or (b)
    you don't understand the specification as it stands. If it is (a) I
    have some sympathy. For example, the standard does not say what
    constitutes a function call. It says that there is a sequence point
    just before the call, but not what happens next. What happens is, of
    course, obvious (control passes to the body of the called function and
    its declarations and statements are executed one after the other) but it
    would be nice if this were stated. Is this omission all that is
    bothering you? If not, what permission do you find for the body of a
    function to have its effect (x = 1) after the call?

    Let's put the sequence point into the program:

    int x<S1>;
    int f(void) {
    x = 1;<S3>
    return 2;<S4>
    }
    int main(void) {
    x = f()<S2>;<S5>
    }

    At S1 x is zero. Sequence point S2 occurs at some point during the
    evaluation of x = f() after the function designator and the arguments
    have been evaluated but before the call. x is still 0 at the point. At
    S3 x must be 1 -- the effect of the assignment must have happened by
    then and won't change at S4. (There are two sequence points here: one
    at the end of the return statement and another just prior to the return
    but I don't think you can tell that there are two). Finally, at S5
    (after the assignment statement in main) x must be 2.

    <snip>
    --
    Ben.
     
    Ben Bacarisse, Jun 19, 2010
    #17
  18. flameice9

    flameice9 Guest

    On Jun 19, 9:20 am, Ben Bacarisse <> wrote:
    > flameice9 <> writes:
    >> On Jun 19, 6:07 am, Ian Collins <> wrote:
    >>> On 06/19/10 11:44 AM, flameice9 wrote:

    >
    > <example snipped because I reproduce it below>
    >
    >>> None, the value of f() still has to be assigned to x.

    >
    >> Yes, but this occurs at an unspecified time between the sequence
    >> point just before x = f() and the sequence point just after it (see
    >> the last sentence of C99 6.5.16p3). Nothing requires x to have the
    >> value of f() after x = f(); is complete. It is allowable that the
    >> x = 1 assignment is performed after the x = f() assignment.

    >
    > How do you arrive at that conclusion?
    >
    > That is a genuine question and there seem to be two possibilities: (a)
    > you feel that some aspects of the language are under-specified or (b)
    > you don't understand the specification as it stands. If it is (a) I
    > have some sympathy.


    It is under-specified.

    > For example, the standard does not say what
    > constitutes a function call. It says that there is a sequence point
    > just before the call, but not what happens next. What happens is, of
    > course, obvious (control passes to the body of the called function and
    > its declarations and statements are executed one after the other) but it
    > would be nice if this were stated. Is this omission all that is
    > bothering you?


    No, this is fine.

    > If not, what permission do you find for the body of a
    > function to have its effect (x = 1) after the call?


    There is no such permission, as the last sentence of 5.1.2.3p2
    requires the effect of x = 1 to occur during the call. This is not
    the problem I was trying to illustrate. The problem is rather that
    the effect of x = f() may occur before the call.

    > Let's put the sequence point into the program:
    >
    > int x<S1>;
    > int f(void) {
    > x = 1;<S3>
    > return 2;<S4>
    > }
    > int main(void) {
    > x = f()<S2>;<S5>
    > }
    >
    > At S1 x is zero. Sequence point S2 occurs at some point during the
    > evaluation of x = f() after the function designator and the arguments
    > have been evaluated but before the call.


    Good so far.

    > x is still 0 at this point.


    Here lies the problem. This is not the case. Before the call, it may
    be deduced both that the call will return (i.e. that control will be
    yielded back) and that the value of f() is always 2. The effect of
    x = f() (i.e. x is assigned 2) may thus occur before the call.

    The problem is in the last sentence of 6.5.16p3:

    The side effect of updating the stored value of the left operand
    shall occur between the previous and the next sequence point.

    This says merely that the effect of x = f() occurs at an unspecified
    time between S1 and S5, which allows it to occur even before S2. It
    is apparent from the wording ("the previous" and "the next" sequence
    points) that this was written considering only the case when there
    are no sequence points between the two sequence points enclosing the
    assignment expression.

    This could be remedied by changing the wording to:

    Let S denote the sequence point immediately after the assignment
    expression. The side effect of updating the stored value of the
    left operand shall occur prior to S, but subsequent to the
    sequence point immediately prior to S.
     
    flameice9, Jun 19, 2010
    #18
  19. flameice9

    jchl Guest

    "Francois Grieu" <> wrote in message
    news:4c1b4b93$0$9840$...
    > Le 18/06/2010 11:28, flameice9 a écrit :
    >> Does the following program invoke undefined behaviour?
    >>
    >> int x;
    >> int f(void) {
    >> x = 1;
    >> return 2;
    >> }
    >> int main(void) {
    >> x = f();
    >> }

    >
    > No. However, in a hosted environment, the termination status returned to
    > the host environment is unspecified.
    > To fix this, before the last } in main() add this line:
    > return 0;
    >
    > Francois Grieu


    Wouldn't the compiler optimise this to just

    int main(void) {
    return 0;
    }

    since it realises x isn't being used so f() will never be called.
     
    jchl, Jun 20, 2010
    #19
  20. flameice9

    Tim Rentsch Guest

    flameice9 <> writes:

    > On Jun 18, 7:25 am, pete <> wrote:
    >> flameice9 wrote:
    >> > This makes sense intuitively, but there appears to be nothing
    >> > requiring a function call to be evaluated prior to its returned value
    >> > being used. Of course, this is possible only for functions for which
    >> > the returned value can be deduced prior to the call.

    >>
    >> Being able to deduce the return value
    >> without the function call actually being made,
    >> only allows the program to omit the function call
    >> if the program has the same behavior
    >> as it would if the function call were actually made.

    >
    > Where is it stated or implied in the standard that in a function call
    > expression, the call occurs prior to the value of the expression being
    > used?


    Please direct your attention to the following passages (the _'s
    indicate emphasis added):

    5.1.2.3p3: In the abstract machine, all expressions _are evaluated as
    specified by the semantics_.

    6.2.4p5: (Entering an enclosed block or calling a function suspends,
    but does not end, execution of the current block.)

    6.5p1: An expression is a sequence of operators and operands _that
    specifies computation of a value_, or ...

    6.5.16.1p2: In simple assignment (=), _the value of the right operand_
    is converted to the type of the assignment expression and
    replaces the value stored in the object designated by the
    left operand. [Semantics of simple assignment.]

    6.8.6.4p2: A return statement terminates execution of the current
    function and returns control to its caller.

    6.8.6.4p3: If a return statement with an expression is executed, _the
    value of the expression is returned to the caller as the
    value of the function call expression_. [Both these last
    two under Semantics of The return statement.]

    The function call is an expression that specifies the computation of a
    value. Where does the value of the function call come from? 6.8.6.4p3
    says it comes from executing a 'return' statement with an expression,
    in particular the 'return' function in the called function body.
    Because the function call's value is produced by executing the 'return'
    statement in the function body, the previous assignment 'x = 1;' must
    have finished storing into the variable x.

    You can imagine other ways that a C program might execute on
    a real machine, but the Standard says it must produce the
    same result as an evaluation on the abstract machine, as
    specified by the stated semantics. The only way to produce
    a value for a function call under these rules is to execute
    a 'return' statement. The value to be assigned simply doesn't
    exist before the 'return' statement is executed.
     
    Tim Rentsch, Jun 20, 2010
    #20
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Ruby Quiz

    [QUIZ] Animal Quiz (#15)

    Ruby Quiz, Jan 14, 2005, in forum: Ruby
    Replies:
    11
    Views:
    405
    James Edward Gray II
    Jan 18, 2005
  2. David Tran
    Replies:
    9
    Views:
    217
    David Tran
    Jan 21, 2005
  3. Ruby Quiz

    [QUIZ] 1-800-THE-QUIZ (#20)

    Ruby Quiz, Feb 18, 2005, in forum: Ruby
    Replies:
    15
    Views:
    343
    gabriele renzi
    Feb 24, 2005
  4. Marcelo Alvim

    [QUIZ] Newbie doubts about the quiz

    Marcelo Alvim, Aug 15, 2006, in forum: Ruby
    Replies:
    15
    Views:
    266
    Marcelo Alvim
    Aug 16, 2006
  5. Daniel Moore
    Replies:
    10
    Views:
    330
    James Gray
    Jan 31, 2009
Loading...

Share This Page