Unexpected output

M

Mazen

Hello,

Following is a simple program:

#include <stdio.h>

int main(void) {
int i = 0, j, k;
j = k = 2;

printf("%d %d\n", i=+j, i=-j);

return 0;
}

The output is
2 2

Shouldn't the second expression be -2 rather than 2? I'm confused.
Your insights pls. Thanks!
 
M

Mazen

The order of evaluation of function arguments is left to the implementation.

--
I remember finding out about you,  |With the nutty taste of wild hickory nuts.
Everyday my mind is all around you,|            I'm whoever you want me to be.
Looking out from my lonely room    |       Annoying Usenet one post at a time.
Day after day.                     |         At least I can stay in character.
Celle est une langue. C'est francais et tres, tres sexuel.

Not sure I understood what you mean.
 
A

arni

Hello,

Following is a simple program:

#include <stdio.h>

int main(void) {
  int i = 0, j, k;
  j = k = 2;

  printf("%d %d\n", i=+j, i=-j);

  return 0;

}

The output is
2 2

Shouldn't the second expression be -2 rather than 2? I'm confused.
Your insights pls. Thanks!

Shouldn't it be i+=j and i-=j?.. Then you'll get 2 -2.
 
E

Eric Sosman

Mazen said:
printf("%d %d\n", i=+j, i=-j);
[...]
The output is
2 2

Shouldn't the second expression be -2 rather than 2? I'm confused.
Your insights pls. Thanks!

The order of evaluation of function arguments is left to the implementation.

It's more serious than that: The behavior is undefined. The
line in question tries to assign to `i' twice without an intervening
sequence point, and the C language makes no promises whatsoever about
what might happen in consequence.

C has two distinct uses for the comma: as an operator, and as
a separator. The comma operator involves a defined order and a
sequence point: `f = x,y' means "first evaluate x and ignore the
value, sequence point, then evaluate y and yield its value, that
value is assigned to f." The comma separator just separates the
elements of a list, without implying any kind of order and without
imposing sequence points. (Unfortunately, the two uses look
distressingly similar.)

In the offending line above, both commas are separators rather
than operators, so no sequence points divide the argument evaluations
from each other. In particular, the two assignments to `i' are not
so divided, hence the undefined behavior.
 
A

arni

[...]
   printf("%d %d\n", i=+j, i=-j);
[...]
   return 0;
[...]
Shouldn't it be i+=j and i-=j?.. Then you'll get 2 -2.

     Or not: The behavior would still be undefined, and for the
same reason as before.

Depends on compiler/optimizer implementation. Anyway, writing code
like that is a very bad practice, you can not be sure what's going to
happen in the end :)
 
M

Morris Keesan

Shouldn't it be i+=j and i-=j?.. Then you'll get 2 -2.

No. If modifying i twice in the argument list weren't undefined,
so that one assignment to i and the evaluation of the corresponding
function argument were guaranteed to be complete before the next
argument was evaluated, printf("%d %d\n", i += j, i -= j) would produce
either "2 0" or "0 -2", depending on the order in which the arguments
are evaluated, which is unspecified (not undefined). The poorly-spaced
code seems to have been intended as printf("%d %d\n", i = +j, i = -j);
 
E

Eric Sosman

[...]
printf("%d %d\n", i=+j, i=-j);
[...]
return 0;
[...]
Shouldn't it be i+=j and i-=j?.. Then you'll get 2 -2.

Or not: The behavior would still be undefined, and for the
same reason as before.

Depends on compiler/optimizer implementation.

The C language is defined by an International Standard, not by
the quirks of any individual compiler. The Standard does not define
any specific behavior for the offending line, nor even any limits on
the possible behaviors.

In particular, there's no guarantee that "you'll get 2 -2."

A particular implementation is free to add (or not) its own
definitions to cover cases the Standard leaves undefined -- but
then you're no longer talking about "C," but about "Frobozz Magic
C Version 4.2 optimization level 3 with #pragma DWIM in effect."
Anyway, writing code
like that is a very bad practice, you can not be sure what's going to
happen in the end :)

Exactly: "What's going to happen" is not defined by the C language.
 
B

BartC

#include <stdio.h>

int main(void) {
int i = 0, j, k;
j = k = 2;

printf("%d %d\n", i=+j, i=-j);

return 0;
}

The output is
2 2

Shouldn't the second expression be -2 rather than 2? I'm confused.

It *is* unintuitive. But printf() is a function, and sometimes the
parameters are evaluated in a funny order:

#include <stdio.h>

int next(void){static int a=0; return ++a;}

int main(void){
printf("%d %d %d\n",next(),next(),next());
}

gives 1 2 3 on one compiler, and 3 2 1 on another (and doubtless some
compiler might give 3 1 2!).

Changing main() to resemble your code:

int main(void){
int i;
printf("%d %d %d",i=next(),i=next(),i=next());
}

Now I get results on 1 2 3, 3 3 3, and 3 2 1 on three different compilers!

For guaranteed results, you need to use a separate printf() call for each
term.
 
M

Mazen

Thanks, Eric. So, how can one achieve the desired result and guarantee a defined behavior?
 
M

Mazen

On 9/10/2011 4:31 PM, arni wrote:
[...]
    printf("%d %d\n", i=+j, i=-j);
[...]
    return 0;
[...]
Shouldn't it be i+=j and i-=j?.. Then you'll get 2 -2.
      Or not: The behavior would still be undefined, and for the
same reason as before.
Depends on compiler/optimizer implementation.

     The C language is defined by an International Standard, not by
the quirks of any individual compiler.  The Standard does not define
any specific behavior for the offending line, nor even any limits on
the possible behaviors.

     In particular, there's no guarantee that "you'll get 2 -2."

     A particular implementation is free to add (or not) its own
definitions to cover cases the Standard leaves undefined -- but
then you're no longer talking about "C," but about "Frobozz Magic
C Version 4.2 optimization level 3 with #pragma DWIM in effect."
Anyway, writing code
like that is a very bad practice, you can not be sure what's going to
happen in the end :)

     Exactly: "What's going to happen" is not defined by the C language.

I have learned the attempting to assign a value to a variable and
fetching the value of it in the same expression will produce an
undefined behaviour. What are some of the other cases that produce
undefined behaviour? This is interesting!

Thanks!
 
J

Joe Pfeiffer

Mazen said:
Thanks, Eric. So, how can one achieve the desired result and guarantee
a defined behavior?

In short, "don't do that".

Getting your desired result depends (of course) on what result you
desired. Assuming your printf() was meant to be

printf("%d %d\n", i = +j, i = -j);

(so you were using an unnecessary '+', as opposed to using the old =+
syntax for += ), then even if it were defined it would be silly. Why
exactly did you assign a value to i, and then assign another value to
it?

If your intent was to print the value of j, print the value of -j, and
set i to -j, here's something that will do it:

printf("%d %d\n", j, i = -j);

If your intent was something else, well, you'd have to do something
else.
 
J

Joe Pfeiffer

Mazen said:
I have learned the attempting to assign a value to a variable and
fetching the value of it in the same expression will produce an
undefined behaviour. What are some of the other cases that produce
undefined behaviour? This is interesting!

That isn't what you should have learned, because that's perfectly well
defined. If your printf() had been

printf("%d ", i = +j);
printf("%d\n", i = -j);

it would have printed the 2 -2 you expected -- though the first
assignment to i would still have been silly, and doing the second
assignment in the printf() would still have been useless obfuscation.

What was undefined was the order in which your three arguments
to printf() were evaluated, in a context where different orders of
evaluation would give different results.

I would be very surprised if anybody actually knows how many ways there
are to provoke undefined output. I supposed searching the standard for
the word "undefined" would help, but of course that would only tell you
all the ways the standard actually says something is undefined, and miss
all the possible things you could do that just don't have definitions.

But, frankly, the only reason to want to know what isn't defined is to
avoid doing it. And "don't write obviously silly code" (like your
original printf() ) is one of the most basic rules for doing that.
 
B

Ben Bacarisse

Mazen said:
I have learned the attempting to assign a value to a variable and
fetching the value of it in the same expression will produce an
undefined behaviour. What are some of the other cases that produce
undefined behaviour? This is interesting!

If that were true, C would not allow:

x = x + 1;

The wording is:

"Between the previous and next sequence point an object shall have its
stored value modified at most once by the evaluation of an
expression. Furthermore, the prior value shall be read only to
determine the value to be stored."

so you may read the value (x) to determine the value to be stored (x +
1). However, in your case, the problem was modifying the value twice.

To understand the rule, you have to know where the sequence points are in
a C program. The standard has a list (edited here for clarity):

1. The call to a function, after the arguments have been evaluated

2. The end of the first operand of the following operators: logical
AND &&; logical OR ||; conditional ?; comma , .

3. The end of a full declarator: declarators.

4. The end of a full expression: an initializer; the expression in an
expression statement; the controlling expression of a selection
statement (if or switch); the controlling expression of a while or
do statement; each of the expressions of a for statement; the
expression in a return statement.

5. Immediately before a library function returns.

6. After the actions associated with each formatted input/output
function conversion specifier.

7. Immediately before and immediately after each call to a comparison
function, and also between any call to a comparison function and
any movement of the objects passed as arguments to that call.

As has been pointed out, the comma in number 2 is the operator and does
not appear in a normal function call -- that comma is just syntax for
the call. Number 7 is about the internals of the qsort and bsearch
library functions.
 
N

Nick Keighley

That isn't what you should have learned, because that's perfectly well
defined.  If your printf() had been

  printf("%d ", i = +j);
  printf("%d\n", i = -j);

it would have printed the 2 -2 you expected -- though the first
assignment to i would still have been silly, and doing the second
assignment in the printf() would still have been useless obfuscation.

What was undefined was the order in which your three arguments
to printf() were evaluated, in a context where different orders of
evaluation would give different results.

I would be very surprised if anybody actually knows how many ways there
are to provoke undefined output.

I think there's an appendix in the standard that lists the undefined
bahaviours


 I supposed searching the standard for
 
K

Kenny McCormack

a defined behavior?

What is the desired result?

That was clearly stated in the OP, but I forget it at the moment. I think
it was "2 2".

Anyway, the best way to fix the program is to replace the printf() statement
(and most of the declarations) with:

puts("2 2");

--

Some of the more common characteristics of Asperger syndrome include:

* Inability to think in abstract ways (eg: puns, jokes, sarcasm, etc)
* Difficulties in empathising with others
* Problems with understanding another person's point of view
* Hampered conversational ability
* Problems with controlling feelings such as anger, depression
and anxiety
* Adherence to routines and schedules, and stress if expected routine
is disrupted
* Inability to manage appropriate social conduct
* Delayed understanding of sexual codes of conduct
* A narrow field of interests. For example a person with Asperger
syndrome may focus on learning all there is to know about
baseball statistics, politics or television shows.
* Anger and aggression when things do not happen as they want
* Sensitivity to criticism
* Eccentricity
* Behaviour varies from mildly unusual to quite aggressive
and difficult
 
B

BartC

Mazen said:
Thanks, Eric. So, how can one achieve the desired result and guarantee a
defined behavior?

Possibly something like:

printf("%d", i=+j);
printf(" %d\n", i=-j);

Or, if you don't care about the value of i at the end (and above, the first
assignment to i has no purpose):

printf("%d %d\n", +j, -j);

would work as well.
 
K

Keith Thompson

Mazen said:
I have learned the attempting to assign a value to a variable and
fetching the value of it in the same expression will produce an
undefined behaviour.

As Joe Pfeiffer points out, that's not quite correct.
What are some of the other cases that produce
undefined behaviour? This is interesting!

Grab a copy of the latest C99 draft from

http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf

and read section J.2.
 
J

James Kuyper

I think there's an appendix in the standard that lists the undefined
bahaviours

I don't think you said what you meant to say: "undefined behaviors" is a
category that includes all behaviors; a set far easier to describe than
to list. :) The list would be of negligible value even if it the list
could easily be created.

Annex J.2 does list features that program can have that can cause the
behavior to be undefined. Note, however, that it cannot be
all-inclusive. Behavior that is undefined "by omission of any explicit
definition of behavior" (4p6), is inherently difficult to identify and list.
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,057
Latest member
KetoBeezACVGummies

Latest Threads

Top