|
Prev: [C and C++] && Operator precedence
Next: 全香港最濺IT Manager http://geocities.com/it_super_manager/
From: Ulrich Eckhardt on 7 Apr 2008 16:34 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 7 Apr 2008 18:12 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 7 Apr 2008 18:42 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 7 Apr 2008 20:20 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 7 Apr 2008 22:48 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
|
Next
|
Last
Pages: 1 2 3 Prev: [C and C++] && Operator precedence Next: 全香港最濺IT Manager http://geocities.com/it_super_manager/ |