From: Ulrich Eckhardt on
Aggro wrote:
> I would like to know the answer to this for both C and C++ as I use both
> languages (usually in differen projects).
>
> Assume the code
> if( A && B )
>
> Normally A is executed before B

No. If A yields false, B is not executed at all. This is called
short-circuit evaluation. Note that in C++ you are actually able to
override operator && and then it's a normal function call which means that
both arguments are evaluated, though their order is unspecified.


> But recently I got second hand information that the execution order is
> not quaranteed. E.g. B could be executed before A by some compilers.

Not by conforming ones, due to the short-circuit rule.

> Different execution order could cause e.g. application to crash if we
> first test is the pointer valid and then call a function for that pointer:
> if( p && p->func() )

This code is fine.

I would try to limit use of this feature though, because it has rather
surprising semantics. Above example is IMHO okay though.

Uli

From: Philip Potter on
Aggro wrote:
> I would like to know the answer to this for both C and C++ as I use both
> languages (usually in differen projects).
>
> Assume the code
> if( A && B )
>
> Normally A is executed before B and this is how I have always believed
> it is guaranteed to work. But recently I got second hand information
> that the execution order is not quaranteed. E.g. B could be executed
> before A by some compilers.
>
> Different execution order could cause e.g. application to crash if we
> first test is the pointer valid and then call a function for that pointer:
> if( p && p->func() )
>
>
> So. Is the execution order guaranteed by the standard in both C and C++
> to be first A and then B or can it change e.g. because of optimization?
> Should I start writing my code in this format to be safe?
>
> if( p )
> if( p->func() )
> ...

Ulrich has answered your question; in C (and probably C++, though I'm
not a C++ expert) both && and || are guaranteed to be executed
left-to-right; and if the result can be generated based on the LHS
alone, the RHS is guaranteed not to be evaluated. Moreover, && and ||
introduce a sequence point between LHS and RHS, so expressions such as
(p && x = *p++) are valid (though not recommended).

Few operators (except ?:, the comma operator, and probably one or two
I've forgotten) have similar semantics. The order of evaluation of the
arguments of most operators is unspecified; in particular, f(x) * 0 and
0 * f(x) may (will?) call f() in either case, even though the result
will always be zero. Similarly A & 0 and 0 & A have no guarantees over
order of evaluation and no sequence points. And finally, x++ * x++ is
undefined behaviour, even though x++ || x++ or x++ && x++ are well-defined.

Only && and || are "magical" in this way.

Phil
From: Francis Glassborow on
Philip Potter wrote:
> Aggro wrote:
>> I would like to know the answer to this for both C and C++ as I use both
>> languages (usually in differen projects).
>>
>> Assume the code
>> if( A && B )
>>
>> Normally A is executed before B and this is how I have always believed
>> it is guaranteed to work. But recently I got second hand information
>> that the execution order is not quaranteed. E.g. B could be executed
>> before A by some compilers.
>>
>> Different execution order could cause e.g. application to crash if we
>> first test is the pointer valid and then call a function for that pointer:
>> if( p && p->func() )
>>
>>
>> So. Is the execution order guaranteed by the standard in both C and C++
>> to be first A and then B or can it change e.g. because of optimization?
>> Should I start writing my code in this format to be safe?
>>
>> if( p )
>> if( p->func() )
>> ...
>
> Ulrich has answered your question; in C (and probably C++, though I'm
> not a C++ expert) both && and || are guaranteed to be executed
> left-to-right; and if the result can be generated based on the LHS
> alone, the RHS is guaranteed not to be evaluated. Moreover, && and ||
> introduce a sequence point between LHS and RHS, so expressions such as
> (p && x = *p++) are valid (though not recommended).
>
> Few operators (except ?:, the comma operator, and probably one or two
> I've forgotten) have similar semantics. The order of evaluation of the
> arguments of most operators is unspecified; in particular, f(x) * 0 and
> 0 * f(x) may (will?) call f() in either case, even though the result
> will always be zero. Similarly A & 0 and 0 & A have no guarantees over
> order of evaluation and no sequence points. And finally, x++ * x++ is
> undefined behaviour, even though x++ || x++ or x++ && x++ are well-defined.
>
> Only && and || are "magical" in this way.

However let me re-emphasise that in C++ && and || cn be overloaded by
user written functions when lazy evaluation does NOT happen. It is only
the built in versions of those operators that require strict evaluation
of the left operand first.
From: Hal Vaughan on
Ulrich Eckhardt wrote:

> Aggro wrote:
>> I would like to know the answer to this for both C and C++ as I use both
>> languages (usually in differen projects).
>>
>> Assume the code
>> if( A && B )
>>
>> Normally A is executed before B
>
> No. If A yields false, B is not executed at all. This is called
> short-circuit evaluation. Note that in C++ you are actually able to
> override operator && and then it's a normal function call which means that
> both arguments are evaluated, though their order is unspecified.
>
>
>> But recently I got second hand information that the execution order is
>> not quaranteed. E.g. B could be executed before A by some compilers.
>
> Not by conforming ones, due to the short-circuit rule.
>
>> Different execution order could cause e.g. application to crash if we
>> first test is the pointer valid and then call a function for that
>> pointer: if( p && p->func() )
>
> This code is fine.

I've seen something like this used in Perl where you can test if an object
or variable is defined by something like:

if ($p) ...

Does it work that way in C and C++? I didn't expect it to, but that code
example implies that you can do:

if (p)...

and if p is defined it evaluates as true and if p isn't defined, it
evaluates as false.

Is that correct and is that acceptable usage in C and C++?

Thanks!

Hal
From: Jack Klein on
On Tue, 08 Apr 2008 00:20:31 GMT, Hal Vaughan <hal(a)halblog.com> wrote
in alt.comp.lang.learn.c-c++:

> Ulrich Eckhardt wrote:
>
> > Aggro wrote:
> >> I would like to know the answer to this for both C and C++ as I use both
> >> languages (usually in differen projects).
> >>
> >> Assume the code
> >> if( A && B )
> >>
> >> Normally A is executed before B
> >
> > No. If A yields false, B is not executed at all. This is called
> > short-circuit evaluation. Note that in C++ you are actually able to
> > override operator && and then it's a normal function call which means that
> > both arguments are evaluated, though their order is unspecified.
> >
> >
> >> But recently I got second hand information that the execution order is
> >> not quaranteed. E.g. B could be executed before A by some compilers.
> >
> > Not by conforming ones, due to the short-circuit rule.
> >
> >> Different execution order could cause e.g. application to crash if we
> >> first test is the pointer valid and then call a function for that
> >> pointer: if( p && p->func() )
> >
> > This code is fine.
>
> I've seen something like this used in Perl where you can test if an object
> or variable is defined by something like:
>
> if ($p) ...

That is because Perl is a language that is interpreted at run time,
and objects are created by name at run time as part of the
interpretation process.

> Does it work that way in C and C++? I didn't expect it to, but that code
> example implies that you can do:
>
> if (p)...
>
> and if p is defined it evaluates as true and if p isn't defined, it
> evaluates as false.

This does not test if an object named 'p' has been defined. If
nothing with the name 'p' is in scope, you will get an error message
from a C or C++ compiler.

C and C++ define logical expressions in a specific way. Anything that
evaluates to 0 is considered false. Anything that evaluates to a
non-zero value is true, any non-zero value at all.

So for any scalar type object 'obj', the expression:

if (obj)

....is exactly equivalent to:

if (obj != 0)

Note that I said scalar type, at least in C. Scalar types include all
the arithmetic types such as char, int, long, float, double, and
pointer types. These are also commonly called "built-in" in C++.

Another feature specific to the C language is that a null pointer to
any type will compare equal to a plain integer constant of 0.

So in both C and C++, you can test the results of standard library
functions like this:

FILE *f = fopen("some_file_name", "r");
void *v = malloc(SOME_NUMBER_OF_BYTES);

Each of these functions returns a valid pointer on success, or NULL on
failure. So normally you test them:

if (f != NULL) // file opened OK
if (v == NULL) // memory allocated OK

....and take appropriate action if you could not open the file or
allocate memory.

But in both C and C++, a null pointer compares equal to a constant
expression with a value of 0, so you could just as easily write:

if (f == 0) // file opened OK
if (v == 0) // memory allocated OK

....and finally, evaluating a built-in type all by itself is equivalent
to comparing it to 0, so:

if (f) // f != 0, file opened OK
if (v) // v != 0, memory allocated OK

> Is that correct and is that acceptable usage in C and C++?

Note that the original posters example was testing a pointer for NULL
before using:

if (p && p->func())

If p is a null pointer, the first expression of the && evaluates to 0
so the attempt to call a member function using a null pointer is not
executed.

In C++, there is the additional factor that some standard library
classes and types have overloaded comparison functions that return
true if the object is in a good state and can be used, and false if
the object is in some error state and not ready to use. Consider this
example:

#include <iostream>
#include <fstream>
#include <string>
using namespace std;

int main()
{
for ( ; ; )
{
string fname;
cout << "enter file name: " << flush;
getline(cin, fname);
ifstream myFile(fname.c_str(), ios_base::in);

if (myFile)
{
cout << "Opened " << fname << " OK" << endl;
myFile.close();
}
else
{
cout << "Can't open " << fname << endl;
myFile.clear();
}
}
return 0;
}

And here is some output I get from running it:

enter file name: c:\autoexec.bat
Opened c:\autoexec.bat OK
enter file name: c:\no_file_by_this_name
Can't open c:\no_file_by_this_name
enter file name: c:\boot.ini
Opened c:\boot.ini OK
enter file name:

You can't do this in C, with a structure or array type, only
arithmetic types and pointers.

> Thanks!
>
> Hal

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://c-faq.com/
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.club.cc.cmu.edu/~ajo/docs/FAQ-acllc.html