order of execution

C

copx

I wonder if something like this
would be save/portable:

m = find_slot();
if (m != NOT_FOUND && list[m].state == OK) {
...

The question is: Is it guaranteed
that the "list[m].state == OK" check
is NOT executed if the "m != NOT_FOUND"
is FALSE?


copx
 
J

Joona I Palaste

copx said:
I wonder if something like this
would be save/portable:
m = find_slot();
if (m != NOT_FOUND && list[m].state == OK) {
..
The question is: Is it guaranteed
that the "list[m].state == OK" check
is NOT executed if the "m != NOT_FOUND"
is FALSE?

Yes it is guaranteed.

--
/-- Joona Palaste ([email protected]) ---------------------------\
| Kingpriest of "The Flying Lemon Tree" G++ FR FW+ M- #108 D+ ADA N+++|
| http://www.helsinki.fi/~palaste W++ B OP+ |
\----------------------------------------- Finland rules! ------------/
"Insanity is to be shared."
- Tailgunner
 
E

Emmanuel Delahaye

copx said:
I wonder if something like this
would be save/portable:

m = find_slot();
if (m != NOT_FOUND && list[m].state == OK) {
..

The question is: Is it guaranteed
that the "list[m].state == OK" check
is NOT executed if the "m != NOT_FOUND"
is FALSE?

Yes it is.

Assuming 'p' is a pointer, an expression like

if (p && *p)
{
...

is idiomatic.
 
A

av

Joona said:
copx said:
I wonder if something like this
would be save/portable:
m = find_slot();
if (m != NOT_FOUND && list[m].state == OK) {
..
The question is: Is it guaranteed
that the "list[m].state == OK" check
is NOT executed if the "m != NOT_FOUND"
is FALSE?

Yes it is guaranteed.

Is this something that is a defined behaviour of the ANSI C compiler
standard?

I can think of compilers, which might decide to optimize the above code,into
slightly different assmembly code, when heavy optimization is turned on.

Thanks,
AV.
 
J

Joona I Palaste

av said:
Joona said:
copx said:
I wonder if something like this
would be save/portable:
m = find_slot();
if (m != NOT_FOUND && list[m].state == OK) {
..
The question is: Is it guaranteed
that the "list[m].state == OK" check
is NOT executed if the "m != NOT_FOUND"
is FALSE?

Yes it is guaranteed.
Is this something that is a defined behaviour of the ANSI C compiler
standard?
I can think of compilers, which might decide to optimize the above code,into
slightly different assmembly code, when heavy optimization is turned on.

Yes it is defined behaviour by the ISO (ANSI) C standard. It is not a
compiler-specific optimisation feature.

--
/-- Joona Palaste ([email protected]) ---------------------------\
| Kingpriest of "The Flying Lemon Tree" G++ FR FW+ M- #108 D+ ADA N+++|
| http://www.helsinki.fi/~palaste W++ B OP+ |
\----------------------------------------- Finland rules! ------------/
"Nothing lasts forever - so why not destroy it now?"
- Quake
 
C

Christian Bau

First of all, my newsreader says you set follow-up to "Re: order of
execution". Please try to avoid such nonsense in the future.
Joona said:
copx said:
I wonder if something like this
would be save/portable:
m = find_slot();
if (m != NOT_FOUND && list[m].state == OK) {
..
The question is: Is it guaranteed
that the "list[m].state == OK" check
is NOT executed if the "m != NOT_FOUND"
is FALSE?

Yes it is guaranteed.

Is this something that is a defined behaviour of the ANSI C compiler
standard?

I can think of compilers, which might decide to optimize the above code,into
slightly different assmembly code, when heavy optimization is turned on.


There are two rules for a compiler: First, it has to do everything
exactly as the C Standard says. In this example, the right hand side of
an && must _not_ be evaluated if the left hand side is false. Second,
the compiler can cheat as much as it likes if you can't tell the
difference.

An example:

if (x > 0 && x < 10) ...

Strictly speaking, the compiler must test (x > 0) first. If that is
false, then it must not test (x < 10). However, you could never see the
difference. So the compiler is allowed in this case to test (x < 10)
first or test both conditions simultaneously. You will still get exactly
the same result as if the compiler had gone by the rules.

A second example:

int * p; ...;

if (p != NULL && *p == 10)...

Strictly speaking, the compiler must not test (*p == 10) if p is a null
pointer. Lets say use a computer that would crash when testing *p == 10
if p is NULL. So obviously you _can_ tell the difference if the compiler
cheats, therefore the compiler is not allowed to cheat.

There are computers where testing (*p == 10) would just produce a result
of true or false, even if p is a null pointer. On such a computer, the
compiler would be allowed to cheat, because you couldn't tell the
difference. And it is ok, exactly because you cannot tell the
difference.

Now there might be a computer where it is guaranteed by the hardware
that reading *p will give a value of 0 if p is a null pointer. On such a
computer, the compiler would be allowed to change the whole test to "if
(*p == 10)". Again, you couldn't tell the difference.

So altogether, the compiler can do whatever it likes, as long as it
guarantees that you get exactly the results that you should get
according to the C Standard. In other words, you will get the right
result.
 
E

Eric Gorr

copx said:
I wonder if something like this
would be save/portable:

m = find_slot();
if (m != NOT_FOUND && list[m].state == OK) {
..

The question is: Is it guaranteed
that the "list[m].state == OK" check
is NOT executed if the "m != NOT_FOUND"
is FALSE?

Yes, according to the standard. Of course, there is no accounting for
compiler bugs.
 
D

Derk Gwen

# > Yes it is guaranteed.
#
# Is this something that is a defined behaviour of the ANSI C compiler
# standard?
#
# I can think of compilers, which might decide to optimize the above code,into
# slightly different assmembly code, when heavy optimization is turned on.

The serialisation is defined by the standard. However the compiler rearranges
the code, it cannot have side effects out of the serialisation order. If code
is executed out of serialisation order, the compiler must insure the side
effects (like the order of stores and loads or traps or exceptions) obey
serialisation constraints. So the compiler can begin an load early, before
the subscript guard is evaluated and verified, but if the guard fails and
the load generates an address error, the compiler must insure the error
is suppressed.

Similarly if the guard has a side effect which changes the subscript or
the subscripted element, an early load would have to be nullified and the
correct array element loaded.

Some hardware allows speculative execution with traps and stores held until
it decided that speculative execution is accepted. Also if a guarded exception
can be shown that it will happen in subsequent unguarded code, the code
can be moved in front of the guard with an early exception.

if (0<=m && m<upperbound && A[m]==quark) xyz();
gloop = A[m];

Whether the guard (0<=m && m<upperbound) is true or false, A[m] will still
be loaded. If it is known xyz() changes neither A nor m, the compiler
might load A[m] before the if-statement; if that is an address error, the
same exception would occur regardless of whether the guard is verified. The
location of the exception can change.
 
T

Thomas Stegen

Christian said:
An example:

if (x > 0 && x < 10) ...

Strictly speaking, the compiler must test (x > 0) first. If that is
false, then it must not test (x < 10). However, you could never see the
difference. So the compiler is allowed in this case to test (x < 10)
first or test both conditions simultaneously. You will still get exactly
the same result as if the compiler had gone by the rules.

A second example:

int * p; ...;

if (p != NULL && *p == 10)...

Strictly speaking, the compiler must not test (*p == 10) if p is a null
pointer. Lets say use a computer that would crash when testing *p == 10
if p is NULL. So obviously you _can_ tell the difference if the compiler
cheats, therefore the compiler is not allowed to cheat.

Your point is understood, but the last example is a bit misleading.
The exact same "optimizations" can be in the last case as in the first
one as long as dereferencing a null pointer on that particular platform
is well behaved. The compiler does not quite follow the same rules as
the programmer. A better example of where you can tell the difference
and so the compiler is not allowed to performs such tricks is:

if(p < 0 && p++ < 0)...

Since if a compiler can optimize code by dereferencing a null pointer
under the covers there is nothing wrong with that as it is not bound
by the standard in quite the same way as the programmer. Dereferencing
a null pointer should be seen as a metaphor for some arbitrary
undefined behaviour.
 
M

Micah Cowan

copx said:
I wonder if something like this
would be save/portable:

m = find_slot();
if (m != NOT_FOUND && list[m].state == OK) {
..

The question is: Is it guaranteed
that the "list[m].state == OK" check
is NOT executed if the "m != NOT_FOUND"
is FALSE?

Yes, it is guaranteed.

-Micah
 

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,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top