i = i++;
invokes undefined behavior because i is incremented and assigned to between
the same sequence points. But I'm curious about
int i = 0, *p = &i;
int eval(int n) {
printf("%d, ", *p);
return n;
}
foo() {
i = eval(i++);
printf("%d\n", i);
}
Does a call to foo() invoke undefined behavior here? Which of the two
printf calls, if either, passes an indeterminate value?
(I get "1, 0" with both gcc and MSVC++.)
--Steve
Yes undefined behavior. The printf() in foo() (which has wrong
definition).
--
Ioannis
* Ioannis Vranos
* Programming pages: http://www.noicys.d2g.com
* Alternative URL: http://run.to/noicys
The code is fine. There is always a sequence point right before a
function call, after the arguments have been evaluated; there are
sequence points within eval(); and there is a sequence point right
before a function returns.
So eval()'s argument is 0, *p is updated to 1, and then there is a
sequence point before execution enters eval(). It prints 1, returns 0,
and this 0 is assigned to i and then printed. It is unambiguous.
> (I get "1, 0" with both gcc and MSVC++.)
That's the only correct result.
Gergo
--
Demographic polls show that you have lost credibility across the board.
Especially with those 14 year-old Valley girls.
> Yes undefined behavior. The printf() in foo() (which has wrong
> definition).
What the heck are you babbling about? The %d specifier in printf()
expects an int, and an int is what is being suuplied to it. There's a
slight chance that you're referring to the omission of #include
<stdio.h>, but other than that, I have no idea what you see wrong
about the printf() call in foo().
--
/-- Joona Palaste (pal...@cc.helsinki.fi) ---------------------------\
| Kingpriest of "The Flying Lemon Tree" G++ FR FW+ M- #108 D+ ADA N+++|
| http://www.helsinki.fi/~palaste W++ B OP+ |
\----------------------------------------- Finland rules! ------------/
"As a boy, I often dreamed of being a baseball, but now we must go forward, not
backward, upward, not forward, and always whirling, whirling towards freedom!"
- Kang
The second sentence was an answer to his second question:
"Which of the two printf calls, if either, passes an indeterminate
value?"
> The second sentence was an answer to his second question:
> "Which of the two printf calls, if either, passes an indeterminate
> value?"
Sorry, but AFAIK you are wrong, since AFAIK a function call constitutes
a sequence point.
--
/-- Joona Palaste (pal...@cc.helsinki.fi) ---------------------------\
| Kingpriest of "The Flying Lemon Tree" G++ FR FW+ M- #108 D+ ADA N+++|
| http://www.helsinki.fi/~palaste W++ B OP+ |
\----------------------------------------- Finland rules! ------------/
"This is a personnel commuter."
- Train driver in Scientific American
i = eval(i++);
printf("%d\n", i);
In the above piece of code, the value of i which is passed to printf() is
implementation dependent. Where do you disagree?
> i = eval(i++);
> printf("%d\n", i);
> In the above piece of code, the value of i which is passed to printf() is
> implementation dependent. Where do you disagree?
Please keep the original code in context. For the record, the code was
something like:
#include <stdio.h>
int i=0;
int eval(int n) {
return n;
}
int main(void) {
i=eval(i++);
printf("%d\n", i);
return 0;
}
(I've corrected some errors and simplified the code.)
Now when evaluating "i=eval(i++)" C first evaluates "i++" which is to
be passed as a parameter to eval(). The value of "i++" is 0 and i is
set to 1.
C now makes a copy of this value 0 which it sends to eval(). eval()
returns what it got, namely 0. Now after the function has been called,
"i++" is guaranteed to have been evaluated, so i is now 1, but
evaluating "i=eval(i++)" which has now been reduced to "i=0" sets i to
0.
That's how I figure it out. I don't take either Ioannis's words or my
own words as gospel, so once more, I'd appreciate input from people who
actually, like, know stuff about C.
--
/-- Joona Palaste (pal...@cc.helsinki.fi) ---------------------------\
| Kingpriest of "The Flying Lemon Tree" G++ FR FW+ M- #108 D+ ADA N+++|
| http://www.helsinki.fi/~palaste W++ B OP+ |
\----------------------------------------- Finland rules! ------------/
"Products like that make me wish I could menstruate."
- Andy Richter
> Please keep the original code in context. For the record, the code was
> something like:
>
> #include <stdio.h>
> int i=0;
> int eval(int n) {
> return n;
> }
> int main(void) {
> i=eval(i++);
> printf("%d\n", i);
> return 0;
> }
>
> (I've corrected some errors and simplified the code.)
> Now when evaluating "i=eval(i++)" C first evaluates "i++" which is to
> be passed as a parameter to eval(). The value of "i++" is 0 and i is
> set to 1.
> C now makes a copy of this value 0 which it sends to eval(). eval()
> returns what it got, namely 0. Now after the function has been called,
> "i++" is guaranteed to have been evaluated, so i is now 1, but
> evaluating "i=eval(i++)" which has now been reduced to "i=0" sets i to
> 0.
> That's how I figure it out. I don't take either Ioannis's words or my
> own words as gospel, so once more, I'd appreciate input from people who
> actually, like, know stuff about C.
Since i=i++ is undefined, the expression i=something(i++) is also
undefined. To make it more clear, i is increased before the value has
been returned from something() or after? This is implementation dependent
behavior.
With that logic you could say that since i=i++ is undefined, i=i++,1 is
also undefined. Sorry, before you can actually quote from the C
Standard, or someone with more experience than either of us agrees with
you, I'll stick to my opinion.
--
/-- Joona Palaste (pal...@cc.helsinki.fi) ---------------------------\
| Kingpriest of "The Flying Lemon Tree" G++ FR FW+ M- #108 D+ ADA N+++|
| http://www.helsinki.fi/~palaste W++ B OP+ |
\----------------------------------------- Finland rules! ------------/
"Holy Banana of this, Sacred Coconut of that, Magic Axolotl of the other."
- Guardian in "Jinxter"
Not if something is a function, or if it is a macro that expands to a
construct that does not evaluate the argument, or that contains a
sequence point after its evaluation.
Here are examples for each case:
int something(int i)
{
return i;
}
#define something(i) 42
#define something(i) ((i), 42)
> To make it more clear, i is increased before the value has
> been returned from something() or after?
It is incremented at some point before the following sequence point.
Since both a function call and a return from a function are sequence
points, i's value is incremented and well-defined by the time the
assignment takes place.
Gergo
--
I didn't believe in reincarnation in any of my other lives. I don't see why
I should have to believe in it in this one.
-- Strange de Jim
Annex C:
[#1] The following are the sequence points described in 5.1.2.3:
-- The call to a function, after the arguments have been
evaluated (6.5.2.2).
There exists a sequence point before starting to execute the function.
"i = f(i++);" is defined.
Even inside the function f the object i is accessed, its value is the
incremented one.
paiyi
Thank you Pai-Yi, this is exactly what I thought as well.
--
/-- Joona Palaste (pal...@cc.helsinki.fi) ---------------------------\
| Kingpriest of "The Flying Lemon Tree" G++ FR FW+ M- #108 D+ ADA N+++|
| http://www.helsinki.fi/~palaste W++ B OP+ |
\----------------------------------------- Finland rules! ------------/
"Roses are red, violets are blue, I'm a schitzophrenic and so am I."
- Bob Wiley
> Not if something is a function, or if it is a macro that expands to a
> construct that does not evaluate the argument, or that contains a
> sequence point after its evaluation.
> Here are examples for each case:
> int something(int i)
> {
> return i;
> }
> #define something(i) 42
> #define something(i) ((i), 42)
>> To make it more clear, i is increased before the value has
>> been returned from something() or after?
> It is incremented at some point before the following sequence point.
> Since both a function call and a return from a function are sequence
> points, i's value is incremented and well-defined by the time the
> assignment takes place.
Thank you Gergo, this is exactly what I thought as well.
--
/-- Joona Palaste (pal...@cc.helsinki.fi) ---------------------------\
| Kingpriest of "The Flying Lemon Tree" G++ FR FW+ M- #108 D+ ADA N+++|
| http://www.helsinki.fi/~palaste W++ B OP+ |
\----------------------------------------- Finland rules! ------------/
"No, Maggie, not Aztec, Olmec! Ol-mec!"
- Lisa Simpson
True, a function call *is* a sequence point. But does it work the way that
you imagine? Did all the compiler vendors get it wrong?
dcorbit@DANNFAST c:/tmp
$ cat foo.c
#include <stdio.h>
int foo(int p)
{
printf("in foo, p is %d\n", p);
return p;
}
int main(void)
{
int i=0;
i = foo(i++);
printf("in main, i is %d\n", i);
return 0;
}
dcorbit@DANNFAST c:/tmp
$ gcc -Wall -W -ansi -pedantic foo.c
dcorbit@DANNFAST c:/tmp
$ ./a
in foo, p is 0
in main, i is 0
C:\tmp>cl /Za /W4 /Ox foo.c
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8804 for 80x86
Copyright (C) Microsoft Corp 1984-1998. All rights reserved.
foo.c
Microsoft (R) Incremental Linker Version 6.00.8447
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.
/out:foo.exe
foo.obj
C:\tmp>foo
in foo, p is 0
in main, i is 0
C:\tmp>icl /Za /W4 /Ox foo.c
Intel(R) C++ Compiler for 32-bit applications, Version 6.0 Beta Build
010824Z
Copyright (C) 1985-2001 Intel Corporation. All rights reserved.
icl: NOTE: The evaluation period for this product ends on 15-mar-2002 UTC.
foo.c
Microsoft (R) Incremental Linker Version 6.00.8447
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.
-out:foo.exe
foo.obj
C:\tmp>foo
in foo, p is 0
in main, i is 0
--
C-FAQ: http://www.eskimo.com/~scs/C-faq/top.html
"The C-FAQ Book" ISBN 0-201-84519-9
C.A.P. FAQ: ftp://cap.connx.com/pub/Chess%20Analysis%20Project%20FAQ.htm
> /out:foo.exe
> foo.obj
> -out:foo.exe
> foo.obj
Umm Dann, this is exactly the same behaviour as I described in an
earlier reply to Ioannis when trying to show that "i=eval(i++)" is
defined if eval() is a function. eval() gets passed i's old value, i's
old value is overwritten by the new value, and i's new value is
overwritten back with the old value.
--
/-- Joona Palaste (pal...@cc.helsinki.fi) ---------------------------\
| Kingpriest of "The Flying Lemon Tree" G++ FR FW+ M- #108 D+ ADA N+++|
| http://www.helsinki.fi/~palaste W++ B OP+ |
\----------------------------------------- Finland rules! ------------/
"You could take his life and..."
- Mirja Tolsa
then i=something(i++); is also undefined.
>
>
> If the compiler optimises it out it becomes i=i++;
I can't understand how i=f(i++) is well defined. If "Even inside the
function f the object i is accessed, its value is the
incremented one" then the following code should print 1:
#include <stdio.h>
int main(void)
{
int i=0;
printf("%d\n", i++);
return 0;
}
Instead it prints 0 as expected. So in printf() the value before the
incrementing is passed.
So in the case of a function
int something(int a)
{
return a; /* Or do something else to a */
}
and since i=i++; is undefined
then i=something(i); is also undefined.
If the compiler optimises it out it becomes i=i++;
Consider the function:
int f(int a)
{
return ++a;
}
How we can claim that the behavior of
i=f(i++); is well defined?
The code:
#include <stdio.h>
int f(int a)
{
return ++a;
}
int main(void)
{
int i=0;
i=f(i++);
printf("%d\n", i);
return 0;
}
produces 1 in both of my compilers.
A function call constitutes a sequence point.
i = f(i++) is defined.
i will be set to whatever f returns.
--
Thomas.
Approaching singularity.
> Consider the function:
> int f(int a)
> {
> return ++a;
> }
"return ++a" increments the local variable a and returns its new
(incremented) value. No variable outside the function is updated at
this point.
> How we can claim that the behavior of
> i=f(i++); is well defined?
Very easily. For clarity, assume i is 0 before this expression is
evaluated. C first evaluates "i++", passing 0 to f() (as the parameter
a), and incrementing i, so i is now 1.
Before we can continue evaluating "i=f(i++)" we have to execute the
function f() for the current parameter a, which is now 0. f() updates
its local variable a to 1 and returns its value, i.e. 1.
NOTE: The function f() is utterly oblivious of the expression
"i=f(i++)" and the expression "i=f(i++)" does not know what f()
actually contains.
Now that f() has returned, with the value 1, we can continue
evaluating "i=f(i++)". This now reduces to "i=1", and 1 is what i
shall be.
Ioannis, you have been proven wrong by me, Dann Corbitt, Gergo
Barany and Pai-Yi HSIAO. Why do you persist in making false claims?
--
/-- Joona Palaste (pal...@cc.helsinki.fi) ---------------------------\
| Kingpriest of "The Flying Lemon Tree" G++ FR FW+ M- #108 D+ ADA N+++|
| http://www.helsinki.fi/~palaste W++ B OP+ |
\----------------------------------------- Finland rules! ------------/
"My absolute aspect is probably..."
- Mato Valtonen
It is defined because a function call constitutes a sequence
point. The standard guarantees that all side-effects (such as
incrementing a post incremented variable) are over and done with
by the time a sequence point is reached.
So, in i = f(i++) the following happens
1, i++ is evaluated
2, i is incremented
3, the function is called
In this case there is a sequence point before 3 and therefore the
side effect of the ++(post) operator must be finished before that
point is reached.
In the i = i++ case there are more than two ways this can happen
1, i++ is evaluated
2, i is incremented
3, the value from 1 is assigned to i
or
1, i++ is evaluated
2, the value from 1 is assigned to i
3, i is incremented
There are probably other ways as well. This situation is intentionally
left ambigous to allow optimizations (And the fact that leaving it ambigous
does not harm the language).
Hope this helps.
--
Thomas.
Approaching singularity.
Which is a Good Thing(tm)
1, i is set to 0
2, i++ is evaluated (to 0)
3, i is incremented to 1
4, a is set to the value from 2
5, ++a is evaluated (to 1)
6, a is incremented to 1
7, the value from 5 is returned,
8, i is set to the value from 5
--
Thomas.
Approaching singularity.
The compiler is not allowed to do that. It must retain the sequence point.
The compiler can do anything it likes, as long as it retains the "as-if"
property. Your example above does not.
Recall with a function call, a *copy* of the input parameter is what is
actually passed to the function. It isn't the same object.
Sorry. My reading of your explanation somehow made it sound backwards. I
did not read the earlier posts.
The value of i++ is the original value of i; so f() will recieve the original
value of i, not the incremented value.
-Daniel
Well, thats not exactly true. I think Pai-Yi made a oops (unless someone would
like to correct me).
The value of the expression i++ is whatever i is at the time.
int i = 0;
int p;
p = i++;
the value of p is 0.
So yes, in a function call f(i++), i is incremented before the function is
called, but that doesn't really matter because the value that is passed is
still the original value of i.
-Daniel
int i;
int f(int a){
return i;
}
i=f(i++);
paiyi
(completed & corrected):
#include <stdio.h>
int f( int i ) {
return i;
}
int main ( void ) {
int i = 0;
i = f( i ++ );
printf("%d\n", i );
return 0;
}
D:\DJGPP\projects\test\paiyi>gcc -Wall -ansi -pedantic pai.c -o paitest
D:\DJGPP\projects\test\paiyi>paitest
0
D:\DJGPP\projects\test\paiyi>
Am I missing something?
-Daniel
Daniel,
I'm very happy to see that you have a subdirectory with my name. :-)
What I mean is that inside the function the object 'i' is accessed
with its value equal to the incremented one.
I give you the complete version.
regards,
paiyi
#include<stdio.h>
int i=0;
int f(int a){return i;}
int main(){
i=f(i++);
return 0;
}
>Ioannis Vranos <noicys@no_spam.yahoo.com> scribbled the following:
>> "Steven Kobes" <ko...@u.arizona.edu> wrote in message
>> news:a5itqi$gdk$1...@news.ccit.arizona.edu...
>>> So, I know that
>>>
>>> i = i++;
>>>
>>> invokes undefined behavior because i is incremented and assigned to
>> between
>>> the same sequence points. But I'm curious about
>>>
>>> int i = 0, *p = &i;
>>> int eval(int n) {
>>> printf("%d, ", *p);
>>> return n;
>>> }
>>> foo() {
>>> i = eval(i++);
>>> printf("%d\n", i);
>>> }
>>>
>>> Does a call to foo() invoke undefined behavior here? Which of the two
>>> printf calls, if either, passes an indeterminate value?
>
>> Yes undefined behavior. The printf() in foo() (which has wrong
>> definition).
>
>What the heck are you babbling about? The %d specifier in printf()
>expects an int, and an int is what is being suuplied to it. There's a
>slight chance that you're referring to the omission of #include
><stdio.h>, but other than that, I have no idea what you see wrong
>about the printf() call in foo().
He hasn't included <stdio.h>
This is a constraint violation in C99 and undefined behavior in C89.
In C99, the definition of foo() is illegal.
>
>
>--
>/-- Joona Palaste (pal...@cc.helsinki.fi) ---------------------------\
>| Kingpriest of "The Flying Lemon Tree" G++ FR FW+ M- #108 D+ ADA N+++|
>| http://www.helsinki.fi/~palaste W++ B OP+ |
>\----------------------------------------- Finland rules! ------------/
>"As a boy, I often dreamed of being a baseball, but now we must go forward, not
>backward, upward, not forward, and always whirling, whirling towards freedom!"
> - Kang
--
"Pedants make the best programmers" - Richard Heathfield
"That is probably a misquote, but
I like it nonetheless" - Finny Merrill
Indent-o-meter
01234567
^
Ah, I see. I was thrown off by the 'int a'. I thought you meant f() to receive
i by argument.
In this case, f() will return the incremented value i, yes.
-Daniel
No, they all got it right. You're not accessing i inside your function
foo, you're accessing p, which is a local variable that got the old
value of i. Try:
#include <stdio.h>
int i=0;
int foo(int p)
{
printf("in foo, p is %d and i is %d\n", p, i);
return p;
}
int main(void)
{
i = foo(i++);
printf("in main, i is %d\n", i);
return 0;
}
bash-2.02$ cc foo.c
bash-2.02$ ./a.out
in foo, p is 0 and i is 1
in main, i is 0
There is a sequence point after evaluating the arguments to foo and
before calling it. That guarantees that i has been incremented to 1 and
the value stored back in i before calling the function. The argument to
foo is the result of evaluating i++ which is 0. There is another
sequence point immediately after foo returns, but it is irrelevant in
this case. The value returned by foo is the value of its argument (0),
which is then stored in i. The value of i has not been modified more
than once between sequence points, nor has it been fetched and modified
without an intervening sequence point for any purpose, let alone an
unallowable one. The behavior is well defined.
-Larry Jones
I think if Santa is going to judge my behavior over the last year,
I ought to be entitled to legal representation. -- Calvin
Ok i understood it.
I insisted till i understand completely the damn thing. :)
In few words as the others said, in any function that you do
i=f(i++);
i has always the returned value from the function, and the function gets
the value before i is incremented.
In a few words:
f() gets value of i
i is incremented
i gets the returned value of f() (the incremented one is lost).
Right. I was just under the impression Pai-Yi was asserting some other
behavior; fortunately this was simply a miscommunication.
-Daniel
No oops afterall, Pai-Yi has clarified his intent. See elsethread.
-Daniel
Yes, i had thought exactly the same in the beginning, that's why i made a
printf("%d\n", i++); example.