more on operands' binding and evaluation order

E

Ersek, Laszlo

Hi,

given the following code,

#include <stdio.h>

static int *
ip_incr(int id, int **i)
{
(void)fprintf(stdout, "%d\n", id);
return ++*i;
}

int main(void)
{
int x[4] = { 0 },
*a = x,
*b = x + 1,
*c = x + 2;

*ip_incr(1, &a) = *ip_incr(2, &b) = *ip_incr(3, &c) = 7;
(void)fprintf(stdout, "%d %d %d %d\n", x[0], x[1], x[2], x[3]);
return 0;
}

am I right to think that the program is well defined, and that the output
is (provided no output error occurs)

----v----
A
B
C
0 7 7 7
----^----

where [ABC] is any permutation of [123]?

Thanks,
lacos
 
E

Eric Sosman

Hi,

given the following code,

#include <stdio.h>

static int *
ip_incr(int id, int **i)
{
(void)fprintf(stdout, "%d\n", id);
return ++*i;
}

int main(void)
{
int x[4] = { 0 },
*a = x,
*b = x + 1,
*c = x + 2;

*ip_incr(1, &a) = *ip_incr(2, &b) = *ip_incr(3, &c) = 7;
(void)fprintf(stdout, "%d %d %d %d\n", x[0], x[1], x[2], x[3]);
return 0;
}

am I right to think that the program is well defined, and that the
output is (provided no output error occurs)

----v----
A
B
C
0 7 7 7
----^----

where [ABC] is any permutation of [123]?

As far as I can see, yes. (Although the "any permutation"
bit clashes somewhat with "well defined.") What aspects do you
find suspicious?
 
E

Ersek, Laszlo

Hi,

given the following code,

#include <stdio.h>

static int *
ip_incr(int id, int **i)
{
(void)fprintf(stdout, "%d\n", id);
return ++*i;
}

int main(void)
{
int x[4] = { 0 },
*a = x,
*b = x + 1,
*c = x + 2;

*ip_incr(1, &a) = *ip_incr(2, &b) = *ip_incr(3, &c) = 7;
(void)fprintf(stdout, "%d %d %d %d\n", x[0], x[1], x[2], x[3]);
return 0;
}

am I right to think that the program is well defined, and that the
output is (provided no output error occurs)

----v----
A
B
C
0 7 7 7
----^----

where [ABC] is any permutation of [123]?

As far as I can see, yes. (Although the "any permutation"
bit clashes somewhat with "well defined.")

Indeed, I should have asked if there was "no undefined behavior" in this
program.

What aspects do you find suspicious?

I wrote the snippet for a friend in order to demonstrate the difference
between operand binding and order of evaluation. In particular that the
"right-associativity" of the assignment operator doesn't determine the
order of calls to ip_incr(). I just wanted to double-check the sanity of
my code with your help.

(BTW, compiling the program with gcc (Debian 4.3.2-1.1), ABC resolves to
123, which is the exact reverse of the "intuitive" (in fact unspecified)
order that my friend assumed (in my understanding).)

Thank you very much.
lacos
 
T

Tim Rentsch

Ersek said:
given the following code,

#include <stdio.h>

static int *
ip_incr(int id, int **i)
{
(void)fprintf(stdout, "%d\n", id);
return ++*i;
}

int main(void)
{
int x[4] = { 0 },
*a = x,
*b = x + 1,
*c = x + 2;

*ip_incr(1, &a) = *ip_incr(2, &b) = *ip_incr(3, &c) = 7;
(void)fprintf(stdout, "%d %d %d %d\n", x[0], x[1], x[2], x[3]);
return 0;
}

am I right to think that the program is well defined, and that the
output is (provided no output error occurs)

----v----
A
B
C
0 7 7 7
----^----

where [ABC] is any permutation of [123]?

The program seems more complicated than it needs to be to
illustrate what I think you're trying to illustrate. However,
unless there is some obscure condition I've missed, it has no
undefined behavior.
 
L

Luca Forlizzi

Hi,

given the following code,

#include <stdio.h>

nice example!
I think it has no undefined behavior, as others, more experienced than
me, have already said.
May I ask why you choose to use fprintf(stdout,...) instead of
printf ?
(Given the illustrative nature of the example, using printf may render
the code a little bit simpler)
 
E

Ersek, Laszlo

On 6/21/2010 8:29 AM, Ersek, Laszlo wrote:
#include <stdio.h>

static int *
ip_incr(int id, int **i)
{
(void)fprintf(stdout, "%d\n", id);
return ++*i;
}

int main(void)
{
int x[4] = { 0 },
*a = x,
*b = x + 1,
*c = x + 2;

*ip_incr(1, &a) = *ip_incr(2, &b) = *ip_incr(3, &c) = 7;
(void)fprintf(stdout, "%d %d %d %d\n", x[0], x[1], x[2], x[3]);
return 0;
}
And MSVC (version 14), even with optimizations supposedly disabled
(/Od), optimizes ip_incr() away, and generates the equivalent of:

int main(void)
{
fprintf(stdout,"%d\n",3);
fprintf(stdout,"%d\n",2);
fprintf(stdout,"%d\n",1);
fprintf(stdout,"%d %d %d %d\n",0,7,7,7);
return 0;
}

I was actually a bit curious what evaluation orders different compilers
choose. Thanks for the info!

lacos
 
E

Ersek, Laszlo

Ersek said:
#include <stdio.h>

static int *
ip_incr(int id, int **i)
{
(void)fprintf(stdout, "%d\n", id);
return ++*i;
}

int main(void)
{
int x[4] = { 0 },
*a = x,
*b = x + 1,
*c = x + 2;

*ip_incr(1, &a) = *ip_incr(2, &b) = *ip_incr(3, &c) = 7;
(void)fprintf(stdout, "%d %d %d %d\n", x[0], x[1], x[2], x[3]);
return 0;
}
The program seems more complicated than it needs to be to
illustrate what I think you're trying to illustrate.

Yes, it is positively not "minimal". We started with

a = b = c = 7;

then (after changing types accordingly)

*++a = *++b = *++c = 7;

and then I added the fprintf()'s. There are better ways, probably. Care to
show one? :)

However, unless there is some obscure condition I've missed, it has no
undefined behavior.

Thanks!
lacos
 
E

Ersek, Laszlo

nice example!

Thanks :)

I think it has no undefined behavior, as others, more experienced than
me, have already said.
May I ask why you choose to use fprintf(stdout,...) instead of
printf ?

I like to be able to search for the stream's name.

(Given the illustrative nature of the example, using printf may render
the code a little bit simpler)

In general I don't believe in "simple examples", as in omitting error
handling and working in a different style than otherwise. Missing error
handling creates a false impression. Truth to be told, I don't really like
that I threw away the return values of the fprintf() calls. Once the test
program compiles, it should also honor write errors, eg.

$ ./try >/dev/full

at least with a nonzero exit status.

Cheers,
lacos
 
E

Eric Sosman

[...]
Yes, it is positively not "minimal". We started with

a = b = c = 7;

then (after changing types accordingly)

*++a = *++b = *++c = 7;

and then I added the fprintf()'s. There are better ways, probably. Care
to show one? :)

If the goal is to show that associativity et al. do not govern
evaluation order, I'd suggest stripping away side-effects that don't
really matter and may just act as red herrings. Something like

#include <stdio.h>

static int index(int idx) {
printf ("idx = %d\n", idx);
return idx;
}

int main(void) {
int array[4] = { 0 };
array[index(1)] = array[index(2)] = array[index(3)] = 7;
printf ("array = { %d, %d, %d, %d }\n",
array[0], array[1], array[2], array[3]);
return 0;
}

.... would be similar in spirit to your original, but without the
distractions of pointers-to-pointers and so on.
 
T

Tim Rentsch

Ersek said:
Ersek said:
#include <stdio.h>

static int *
ip_incr(int id, int **i)
{
(void)fprintf(stdout, "%d\n", id);
return ++*i;
}

int main(void)
{
int x[4] = { 0 },
*a = x,
*b = x + 1,
*c = x + 2;

*ip_incr(1, &a) = *ip_incr(2, &b) = *ip_incr(3, &c) = 7;
(void)fprintf(stdout, "%d %d %d %d\n", x[0], x[1], x[2], x[3]);
return 0;
}
The program seems more complicated than it needs to be to
illustrate what I think you're trying to illustrate.

[snip] Care to show one? :)

I would probably write something like this:

#include <stdio.h>

static int x[4];

int *
px( int k ){
printf( "%d\n", k );
return x+k;
}

int
main(){
*px(1) = *px(2) = *px(3) = 7;
printf( "%d %d %d %d\n", x[0], x[1], x[2], x[3] );
return 0;
}
 
E

Ersek, Laszlo

#include <stdio.h>

static int x[4];

int *
px( int k ){
printf( "%d\n", k );
return x+k;
}

int
main(){
*px(1) = *px(2) = *px(3) = 7;
printf( "%d %d %d %d\n", x[0], x[1], x[2], x[3] );
return 0;
}

Thanks!
lacos
 

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

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top