Order of execution

S

Sabiyur

Hi all,
one of the recent post gives the macro to do swap

#define SWAP(m, n) (tmp = (m), (m) = (n), (n) = tmp)

This macro will work, if the execution is from left to right.

That is step 1) tmp=m
step 2) m=n
step 3) n=tmp

But I hope order of execution is decided by the compiler.
Does C specification is saying any thing about this order of exectuion?

Will this macro work on all compilers?

Plz share your thoughts...

Thanks
Sabi
 
R

Roberto Waltman

Sabiyur said:
Hi all,
one of the recent post gives the macro to do swap

#define SWAP(m, n) (tmp = (m), (m) = (n), (n) = tmp)

This macro will work, if the execution is from left to right.

That is step 1) tmp=m
step 2) m=n
step 3) n=tmp

But I hope order of execution is decided by the compiler.
Does C specification is saying any thing about this order of exectuion?

Will this macro work on all compilers?
Yes, it will work on all C compilers. The comma operator used in the
macro guarantees left-to-right evaluation.

(Of course, tmp must be defined first.)
 
R

Richard Bos

Sabiyur said:
one of the recent post gives the macro to do swap

#define SWAP(m, n) (tmp = (m), (m) = (n), (n) = tmp)

This macro will work, if the execution is from left to right.

No, it won't; it will work, _if_ (and that's a much bigger if) tmp has
the same type as m and n, or a compatible one.
That is step 1) tmp=m
step 2) m=n
step 3) n=tmp

But I hope order of execution is decided by the compiler.
Does C specification is saying any thing about this order of exectuion?

Yes. Not generally, but there's a sequence point at the commas. This
means that whatever trickery happens under the bonnet, the program much
at least behave as if it was executed left-to-right.

However, using this macro means that you have to declare a third object;
this object _must_ be called tmp; it must not hold an important value at
the moment this macro is called; and it must be declared to have a type
that is compatible with both m and n (so no using it to swap long
doubles one line, and structs the next line. So much for generality).

All this means that using this macro is probably rather more bother than
just writing this line out every time you need it. At least that means
you can swap several types of value, without having to resort to hacks
such as

{
the_appropriate_type tmp;
SWAP(object_1, object_2_;
}

(Oh, and of course by forgoing the macro you can also swap objects which
are themselves called tmp, but that's a lesser advantage.)

Richard
 
M

Michael Mair

Sabiyur said:
Hi all,
one of the recent post gives the macro to do swap

#define SWAP(m, n) (tmp = (m), (m) = (n), (n) = tmp)

This macro will work, if the execution is from left to right.

That is step 1) tmp=m
step 2) m=n
step 3) n=tmp

But I hope order of execution is decided by the compiler.
Does C specification is saying any thing about this order of exectuion?

Will this macro work on all compilers?

C has a concept called "sequence points".
Between two consecutive sequence points, the order of execution
is not determined by the C standard -- it only has to be
semantically correct.
However, you can be sure that the code before the sequence point
is evaluated after the sequence point (or that your compiler /
platform behaves as if this is the case).
The comma operator gives you such a sequence point, i.e.
the preprocessed version of
tmp = (m)
will be executed before the preprocessed version of
(m) = (n), (n) = tmp
and, applying this rule once more,
(m) = (n)
is executed before
(n) = tmp

Read more on sequence points in the FAQ:
http://c-faq.com/expr/seqpoints.html
and the rest of chapter 3.

Cheers
Michael
 
R

Roberto Waltman

Michael said:
C has a concept called "sequence points".
Between two consecutive sequence points, the order of execution
is not determined by the C standard -- it only has to be
semantically correct.
However, you can be sure that the code before the sequence point
is evaluated <-----> after the sequence point (or that your compiler /

Insert // "before the code that is" \\
 
S

Stephen Sprunk

Sabiyur said:
But I hope order of execution is decided by the compiler.
Does C specification is saying any thing about this order of exectuion?

The compiler can do anything it wants as long as the resulting program
behaves as if it did exactly what you said, i.e. it should be impossible to
detect it's done anything differently.

You'll see this "as if" rule referred to frequently on c.l.c.
Will this macro work on all compilers?

It should work the same on any compiler (there's reasons it may fail, but it
would fail on all in those cases).

S
 
C

Chris Hills

Hi all,
one of the recent post gives the macro to do swap

#define SWAP(m, n) (tmp = (m), (m) = (n), (n) = tmp)

This macro will work, if the execution is from left to right.

That is step 1) tmp=m
step 2) m=n
step 3) n=tmp

But I hope order of execution is decided by the compiler.
Does C specification is saying any thing about this order of exectuion?

Will this macro work on all compilers?

Plz share your thoughts...

http://www.phaedsys.demon.co.uk/chris/sweng/swengtips3.htm
 
G

gangchen.oz

the result I got from following calculation is (i=10, j=2):
(i * j++) + (i * j) = 40
(i * j) + (i * j++) = 40
(i * j--) + (i * j) = 40
(i * j) + (i * j--) = 40
(i * ++j) + (i * j) = 60
(i * j) + (i * ++j) = 60
(i * ++j) + (i * --j) = 40
(i * --j) + (i * ++j) = 40

I realized that the '+' operator is not a sequence point, which means
either left or right part could have side effects. Still feel a little
puzzled, please someone could explain this.
 
R

Richard Heathfield

(e-mail address removed) said:
the result I got from following calculation is (i=10, j=2):
(i * j++) + (i * j) = 40

Undefined behaviour.
(i * j) + (i * j++) = 40

Undefined behaviour.
(i * j--) + (i * j) = 40

Undefined behaviour.
(i * j) + (i * j--) = 40

Undefined behaviour.
(i * ++j) + (i * j) = 60

Undefined behaviour.
(i * j) + (i * ++j) = 60

Undefined behaviour.
(i * ++j) + (i * --j) = 40

Undefined behaviour.
(i * --j) + (i * ++j) = 40

Undefined behaviour.
I realized that the '+' operator is not a sequence point, which means
either left or right part could have side effects. Still feel a little
puzzled, please someone could explain this.

Undefined behaviour - and the C Standard does not attempt to explain or
predict the results of undefined behaviour.

In other words, when you break the rules, you're on your own.
 
R

Roberto Waltman

the result I got from following calculation is (i=10, j=2):
(i * j++) + (i * j) = 40
(i * j) + (i * j++) = 40
(i * j--) + (i * j) = 40
(i * j) + (i * j--) = 40
(i * ++j) + (i * j) = 60
(i * j) + (i * ++j) = 60
(i * ++j) + (i * --j) = 40
(i * --j) + (i * ++j) = 40

I realized that the '+' operator is not a sequence point, which means
either left or right part could have side effects.

The would "have side effects" (changing the value of j) even if there
was a sequence point.
Still feel a little
puzzled, please someone could explain this.

They all invoke undefined behavior, so anything can happen.
Contrary to popular believe in comp.lang.c, this does not mean that
demons may fly out of your nose, but that the compiler is not required
to interpret these statements in any one well defined way, or to do
anything that is consistent and repeatable, or to do anything that
looks "reasonable" to you.

Let's take the first example:

/* result = */ (i * j++) + (i * j) /* ; */

A compiler could translate this as if it was written in either one of
the following ways (and an infinite number of others.). None of them
is "incorrect".

(Lets assume i, j, tmp1, tmp2, tmp3 and result are all declared as
plain int.)

=====
tmp1 = i * j;
tmp2 = i * j;
j++;
result = tmp1 + tmp2;
====
tmp1 = i * j;
j++;
tmp2 = i * j;
result = tmp1 + tmp2;
=====
tmp1 = i * j;
tmp3 = j;
j = A_RANDOM_VALUE; /* In some architectures */
/* with multiple execution */
/* units, the increment was */
/* scheduled to run in */
/* parallel with following */
/* code, and the value of j */
/* is retrieved before the */
/* operation has been */
/* completed. */
/* Some architectures could */
/* trap this and terminate */
/* the program here. */
tmp2 = i * j;
j = tmp3 + 1;
result = tmp1 + tmp2;
=====
 
R

Richard Heathfield

Roberto Waltman said:

They all invoke undefined behavior, so anything can happen.
Contrary to popular believe in comp.lang.c, this does not mean that
demons may fly out of your nose,

Chapter and verse, please. :)
 
K

Kenneth Brody

Roberto said:
On 29 Jun 2006 08:37:28 -0700, (e-mail address removed) wrote: [...]
Still feel a little
puzzled, please someone could explain this.

They all invoke undefined behavior, so anything can happen.
Contrary to popular believe in comp.lang.c, this does not mean that
demons may fly out of your nose but that the compiler is not required
to interpret these statements in any one well defined way, or to do
anything that is consistent and repeatable, or to do anything that
looks "reasonable" to you.
[...]

And causing demons to fly out your nose is a perfectly valid way to
"interpret these statements", as far as the standard is concerned.

While it is highly unlikely that a compiler writer will go out of
his way to cause such behavior, there is nothing stopping one from
creating such behavior, and such behavior would still be conforming
to the standard.

The odds are that behaviour of code with things like "j++ + j" will
be one of two scenarios (returning either "j+j" or "j+j+1", with j
being incremented by one in both cases), but that is only because
the compiler writer simply allowed the undefined behavior to be
ignored, and treated the "j++" as if it were any other instance of
"j++" in a valid statement.

However, "the odds are" is not the same as "the standard requires",
and "undefined behavior" is exactly that -- undefined. The standard
places absolutely no restrictions on the outcome, and does not
prohibit the creation of nasal demons.

--
+-------------------------+--------------------+-----------------------+
| Kenneth J. Brody | www.hvcomputer.com | #include |
| kenbrody/at\spamcop.net | www.fptech.com | <std_disclaimer.h> |
+-------------------------+--------------------+-----------------------+
Don't e-mail me at: <mailto:[email protected]>
 
C

Chris Hills

Richard Heathfield said:
(e-mail address removed) said:


Undefined behaviour.


Undefined behaviour.


Undefined behaviour.


Undefined behaviour.


Undefined behaviour.


Undefined behaviour.


Undefined behaviour.


Undefined behaviour.


Undefined behaviour - and the C Standard does not attempt to explain or
predict the results of undefined behaviour.

In other words, when you break the rules, you're on your own.

See the page linked to the one with the above lines

http://www.phaedsys.demon.co.uk/chris/sweng/swengtips3a.htm
 
C

Chris Hills

the result I got from following calculation is (i=10, j=2):
(i * j++) + (i * j) = 40
(i * j) + (i * j++) = 40
(i * j--) + (i * j) = 40
(i * j) + (i * j--) = 40
(i * ++j) + (i * j) = 60
(i * j) + (i * ++j) = 60
(i * ++j) + (i * --j) = 40
(i * --j) + (i * ++j) = 40

I realized that the '+' operator is not a sequence point, which means
either left or right part could have side effects. Still feel a little
puzzled, please someone could explain this.

There is no defined way of processing a line. Some work left to right
others right to left and some middle out etc. With others it depends on
how the optimiser works on that particular architecture as to how it
does it.


I assume everyone also looked at the linked page

http://www.phaedsys.demon.co.uk/chris/sweng/swengtips3a.htm

which gave the outputs from several compilers highlighting the fact that
it is all Undefined Behaviour.

As it happens that line of above "results" is not the same as the other
FIVE versions recorded!!!

What was the compiler used? Does any one have any more differing
results. I will expand the table.
 
C

Chris Hills

Richard Heathfield said:
Chris Hills said:


If you're interested in the results for some of the compilers I have here
that don't appear to be in your list, please post the source. (I started
typing it in, and got very bored very quickly!)


This was to run on a Keil C51 targeting a Philips 80C592 edit to as
required..

#include <REG592.H>
#include <inttypes.h>
#include <stdio.h>

static void init_serial(void);

void main(void)
{
uint16_t i = 10;
uint16_t j = 0;

init_serial();

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

}
 
R

Robert Gamble

Chris said:
This was to run on a Keil C51 targeting a Philips 80C592 edit to as
required..

#include <REG592.H>
#include <inttypes.h>
#include <stdio.h>

static void init_serial(void);

void main(void)
{
uint16_t i = 10;
uint16_t j = 0;

init_serial();

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

Something's wrong here...
j=2;
printf(" (i * ++j ) + (i * j) = %d \n",(i * --j ) + (i * j ));

And here.

Robert Gamble
 
R

Richard Heathfield

Chris Hills said:
This was to run on a Keil C51 targeting a Philips 80C592 edit to as
required..

I lost the two strange headers and the prototype, changed void main to int
main, added a return statement, and changed uint16_t to int, to match the
printfs. I then compiled the program on three different compilers (two
different operating systems).

Here are my results:

gcc Microsoft C Borland C
2.95.3 12.00.8168 5.6
Linux Windows XP Windows XP
---------------------------------
20 20 20
30 30 30
20 20 20
10 10 10
40 40 <------> 50
40 40 <------> 50
40 40 <------> 50
40 40 <------> 30
20 20 20
60 <------> 50 50
40 <------> 50 50
40 <------> 30 30

All three of these results differ from each other and from all of your
published results in at least one respect (marked <------> for your
convenience).
 
R

Roberto Waltman

Kenneth said:
Roberto said:
(e-mail address removed) wrote: [...]
Still feel a little
puzzled, please someone could explain this.

They all invoke undefined behavior, so anything can happen.
Contrary to popular believe in comp.lang.c, this does not mean that
demons may fly out of your nose but that the compiler is not required
to interpret these statements in any one well defined way, or to do
anything that is consistent and repeatable, or to do anything that
looks "reasonable" to you.
[...]

And causing demons to fly out your nose is a perfectly valid way to
"interpret these statements", as far as the standard is concerned.

While it is highly unlikely that a compiler writer will go out of
his way to cause such behavior,

You didn't spend much time around compiler writers, did you? :)
there is nothing stopping one from
creating such behavior, and such behavior would still be conforming
to the standard.

The odds are that behaviour of code with things like "j++ + j" will
be one of two scenarios (returning either "j+j" or "j+j+1", with j
being incremented by one in both cases), but that is only because
the compiler writer simply allowed the undefined behavior to be
ignored, and treated the "j++" as if it were any other instance of
"j++" in a valid statement.

However, "the odds are" is not the same as "the standard requires",
and "undefined behavior" is exactly that -- undefined. The standard
places absolutely no restrictions on the outcome, and does not
prohibit the creation of nasal demons.

I understand that perfectly well. I am aware that asking a compiler to
process something like "i = i++ + ++i;" could cause any, or all, or
any combination of the following to happen, without violating the C
standard:

a) The customary appearance of nasal demons.
b) Peace on Earth to all men of goodwill.
c) The discovery that ether and phlogiston are responsible, after all,
for the propagation of electromagnetic waves and heat, respectively.
d) The reversal of the movement of the planet's tectonic plates,
putting South America and Africa in a collision course. (You have been
warned, visit Buenos Aires while you can.)
e) The discovery of weapons of mass destruction in Iraq.
f) The selective reversal of the magnetic field on the platters in my
hard disk, in such a way that my Ubuntu Linux box will be downgraded
to a legitimate copy of Windows Vista, Service Pack 72.

Still, while presenting things this way may elicit a chuckle from
comp.lang.c veterans, it is not the right pedagogical approach to be
used when answering questions from beginners.
I believe the way my answer was worded was both correct and more
helpful to the OP.
Let's bring up the nasal demons later, when he is mature enough and
strong enough to face the truth.

Amicably yours,

Roberto Waltman.
 

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,764
Messages
2,569,565
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top