#168866 - sverx - Mon Jun 01, 2009 9:51 am
... sometimes I feel a beginner even more than what I am in fact [;)]
The question, made short, is: would be a second condition after an OR evaluated if the first condition is already true (same with AND and false)? I mean, let's say we have
Code: |
if ((a==5) || (b==6)) <do something> |
The condition (b==6) would ever be evaluated if (a==5) is true?
And what if the code is like
Code: |
if ((a==5) || (++b==6)) <do something> |
then?
(I'm asking this question also because I remember that once, when I was programming with Borland's Pascal, there was a compiler option called somewhat like "short circuit evaluation"...)
Thanks! :)
#168867 - Dwedit - Mon Jun 01, 2009 10:48 am
I'm pretty sure that short circuit evaluation is the standard.
_________________
"We are merely sprites that dance at the beck and call of our button pressing overlord."
#168870 - vuurrobin - Mon Jun 01, 2009 12:06 pm
I believe that || is short circuit and | is long circuit evaluation if both sides are boolean values (bitwise OR with only 1 bit is pretty much the same as boolean wise OR).
#168871 - Kyoufu Kawa - Mon Jun 01, 2009 1:45 pm
I don't believe that's right, vuurrobin. Double || is "if this or that", a boolean operation that uses true or false conditions, while | is "this OR'd with that", a binary operation that changes the value of "this".
Same with & (and).
Edit: Note that if you use single | in a conditional... Code: |
if (this | that) ... |
and "this" ends up nonzero, it will evaluate to true. This behavior is related to using assignment = instead of comparison ==.
Edit 2: it also depends on what the boolean values are. We don't all use C++.
#168872 - Mighty Max - Mon Jun 01, 2009 2:14 pm
|| doesn't evaluate the remaining part if it the statement is already a tautology. Let a be a boolean (a || !a) && (!a || a) will only do 3 checks and skips one and evaluate directly to true.
| will evaluate both sides, because it will bitwise operate and has a bit value, not a strict boolean as a result. It doesn't matter if it is a int-type boolean or a another specific implementation. Let a be int or boolean or any other ordinal (a | ~a) & (~a | a) evaluates to the same type as a with the value ~0 (-> true) all elements are included in the calculation.
_________________
GBAMP Multiboot
#168874 - Kyoufu Kawa - Mon Jun 01, 2009 3:03 pm
You can't really call | a comparison, though, can you? It's an assigment whose end result is compared, right?
#168876 - gauauu - Mon Jun 01, 2009 3:22 pm
Kyoufu Kawa wrote: |
You can't really call | a comparison, though, can you? It's an assigment whose end result is compared, right? |
Not sure what you mean by being an assignment -- it's an operator, just like + and - are. (Although I would agree that you wouldn't generally call it a comparison operator) If you use |=, you will be doing assignment.
#168877 - Mighty Max - Mon Jun 01, 2009 3:27 pm
|| would fall under the same definition. (bool x bool) -> bool is an operation.
So yes i can call it an compare, Only that the equivalences of it create not 2 partitions, but 2^bits_per_word.
Taken the (bool) cast, it then again does map to a boolean compare ... (and that cast is implizit for an if and such)
_________________
GBAMP Multiboot
#168879 - Kyoufu Kawa - Mon Jun 01, 2009 3:54 pm
Okay now my head hurts. Thanks.
#168911 - sgeos - Tue Jun 02, 2009 7:54 am
This is easy to check.
Code: |
#include <stdio.h>
#define OPERATION ||
#define STRINGIZE_(a) #a
#define STRINGIZE(a) STRINGIZE_(a)
#define EVALUATE(a) subroutine(#a, a)
int subroutine(const char *pName, int pValue)
{
printf("%s = %d\n", pName, pValue);
return pValue;
}
int main(void)
{
int value[2] = {-1, 1};
printf("if ( %s %s %s )\n",
STRINGIZE(value[0]), STRINGIZE(OPERATION), STRINGIZE(value[1]));
if ( EVALUATE(value[0]) OPERATION EVALUATE(value[1]) )
printf("if condition met\n");
else
printf("else condition met\n");
return 0;
} |
The output is:
Code: |
$ ./short.exe
if ( value[0] || value[1] )
value[0] = -1
if condition met |
Only the first condition is tested. Try changing the operation macro and see what happens. =)
#168912 - elwing - Tue Jun 02, 2009 8:21 am
rather than trying to find theory, shouldn't we check ansi standard? i'm pretty sure that this is defined... that said perform the test, i wouldn't bet every compiler follows the norms exactly...
#168913 - elwing - Tue Jun 02, 2009 8:38 am
from ISO/IEC 9899:TC3 Committee Draft ? Septermber 7, 2007 WG14/N1256:
Quote: |
6.5.11 Bitwise exclusive OR operator
Syntax
1 exclusive-OR-expression:
AND-expression
exclusive-OR-expression ^ AND-expression
Constraints
2 Each of the operands shall have integer type.
Semantics
3 The usual arithmetic conversions are performed on the operands.
4 The result of the ^ operator is the bitwise exclusive OR of the operands (that is, each bit
in the result is set if and only if exactly one of the corresponding bits in the converted
operands is set).
6.5.12 Bitwise inclusive OR operator
Syntax
1 inclusive-OR-expression:
exclusive-OR-expression
inclusive-OR-expression | exclusive-OR-expression
Constraints
2 Each of the operands shall have integer type.
Semantics
3 The usual arithmetic conversions are performed on the operands.
4 The result of the | operator is the bitwise inclusive OR of the operands (that is, each bit in
the result is set if and only if at least one of the corresponding bits in the converted
operands is set).
6.5.13 Logical AND operator
Syntax
1 logical-AND-expression:
inclusive-OR-expression
logical-AND-expression && inclusive-OR-expression
Constraints
2 Each of the operands shall have scalar type.
Semantics
3 The && operator shall yield 1 if both of its operands compare unequal to 0; otherwise, it
yields 0. The result has type int.
4 Unlikethe bitwise binary & operator,the && operator guarantees left-to-right evaluation;
there is a sequence point after the evaluation of the first operand. If the first operand
compares equal to 0, the second operand is not evaluated.
6.5.14 Logical OR operator
Syntax
1 logical-OR-expression:
logical-AND-expression
logical-OR-expression || logical-AND-expression
Constraints
2 Each of the operands shall have scalar type.
Semantics
3 The || operator shall yield 1 if either of its operands compare unequal to 0; otherwise, it
yields 0. The result has type int.
4 Unlikethe bitwise | operator,the || operator guarantees left-to-right evaluation; there is
asequence point after the evaluation of the first operand. If the first operand compares
unequal to 0, the second operand is not evaluated. |
guess vuurrobin was right (for the norm at least)
Quote: |
I believe that || is short circuit and | is long circuit evaluation if both sides are boolean values (bitwise OR with only 1 bit is pretty much the same as boolean wise OR). |
#168919 - Miked0801 - Tue Jun 02, 2009 5:26 pm
In anycase, doing:
Code: |
if ((a==5) || (++b==6)) <do something>
|
Would get you fired as a professional coder. Seriously, if you have to really think about what a statement is doing and there is a much, much easier way to do it, then do it the easier way:
Code: |
if(a==5)
{
something();
}
else
{
++b;
if(b == 6)
{
something();
}
}
|
Or don't short circuit it and do the increment always. It matter little :)
#168920 - gauauu - Tue Jun 02, 2009 7:33 pm
Miked0801 wrote: |
Or don't short circuit it and do the increment always. It matter little :) |
Yes, what he said. But (based on our previous conversation) don't take that to mean that
Code: |
if ((a==5) | (++b==6)) <do something>
|
is a good idea either -- although it should work, and avoid the short-circuiting, the fact that we have this whole thread discussing whether that works goes to show that it can be confusing. Clarity is more important.
#168921 - Tyler24 - Wed Jun 03, 2009 2:43 am
Quote: |
Would get you fired as a professional coder. |
They're that serious in the real world, eh?
#168922 - Dwedit - Wed Jun 03, 2009 3:12 am
Read www.thedailywtf.com to see what "Professionals" can get away with.
_________________
"We are merely sprites that dance at the beck and call of our button pressing overlord."
#168923 - elwing - Wed Jun 03, 2009 6:46 am
that said i have already seen much worst code from professional consulting entreprise...
I'll correct the issue... you might get fired with such a piece of code
#168924 - sgeos - Wed Jun 03, 2009 7:38 am
elwing wrote: |
you might get fired with such a piece of code |
You should hear about it, at the very least. You might get fired, you might be put on probation. On the otherhand, some companies don't care about much of anything.
FWIW, I totally missed ++b part of the code. Such expressions should live on lines of their own. See Miked0801's post an example of good coding practice.
Often theoretical questions can be most compactly illustrated using bad coding practices. If this is the case, fine, but again, such compact code can be easily tested. If the behavior is not undefined, a compliant compiler will produce standard behavior by definition. A few changes to the previous test program yield the following output:
Code: |
$ ./short.exe
int a = 5;
int b = 5;
if ( (a == 5) || (++b == 6) )
// (a == 5) == 1
// if condition met |
Source:
Code: |
#include <stdio.h>
#define OPERATION ||
#define VALUE_A 5
#define VALUE_B 5
#define VALUE_TEST_A 5
#define VALUE_TEST_B 6
#define TEST_A(a) (a == VALUE_TEST_A)
#define TEST_B(a) (++a == VALUE_TEST_B)
#define STRINGIZE_(a) #a
#define STRINGIZE(a) STRINGIZE_(a)
#define EVALUATE(a) printExpressionValue(STRINGIZE_(a), a)
int printExpressionValue(const char *pExpression, int pValue)
{
printf("// %s == %d\n", pExpression, pValue);
return pValue;
}
int main(void)
{
int a = VALUE_A;
int b = VALUE_B;
printf("int a = %d;\nint b = %d;\n", a, b);
printf("if ( %s %s %s )\n", STRINGIZE(TEST_A(a)),
STRINGIZE(OPERATION), STRINGIZE(TEST_B(b)));
if ( EVALUATE(TEST_A(a)) OPERATION EVALUATE(TEST_B(b)) )
printf(" // if condition met\n");
else
printf(" // else condition met\n");
return 0;
} |
#168925 - kusma - Wed Jun 03, 2009 10:30 am
Tyler24 wrote: |
They're that serious in the real world, eh? |
Not really. As a matter of fact, I think he's wrong. There's nothing wrong with constructs like that IMO. Sure, the variables shouldn't be named "a" and "b", and perhaps there should be a comment explaining the logic behind the code, but there's nothing wrong with using statements like that IMO. And I've seen people keep their jobs over way, WAY worse code than that.
Personally, I'd write it as
Code: |
if (5 !=a) ++b;
if (5 == a || 6 == b) <code> |
...but that's purely out of preference.
#168926 - sverx - Wed Jun 03, 2009 10:41 am
Oh, how many replies! Didn't expect that!
So, it seems to me that I understood that if I'm using the || operator then a "second" comparison will be made only if the "first" isn't TRUE, and the same with && operator and having the first part not FALSE (thus it's actually what Borland's Pascal called "short circuit evaluation") right? Everyone agree?
btw:
Quote: |
In anycase, doing:
Code: | if ((a==5) || (++b==6)) <do something> |
Would get you fired as a professional coder. |
Fortunatly [;)] that was just for example, I'm not doing anything like that. (Actually I also prefer to keep the code as simple as possible, even if I have to write few more lines to achieve the same...)
The question originally entered my head because I wanted to check if a pointer was NULL or not and, if it wasn't null, if was NULL one of the pointer of the struct pointed by the first pointer. So I had something like that
Code: |
if (ptr!=NULL)
if (ptr->son_ptr!=NULL)
<do something> |
and I was asking myself if writing
Code: |
if ((ptr!=NULL) && (ptr->son_ptr!=NULL))
<do something> |
would potentially lead to a problem when cheking the second condition if the pointer was NULL. I hope I explained well enough...
Thanks everyone :)
#168927 - kusma - Wed Jun 03, 2009 10:52 am
sverx wrote: |
So, it seems to me that I understood that if I'm using the || operator then a "second" comparison will be made only if the "first" isn't TRUE, and the same with && operator and having the first part not FALSE (thus it's actually what Borland's Pascal called "short circuit evaluation") right? Everyone agree? |
Yes. This is a guarantee that K&R gives. Short circuiting (although I believe it's not called that by K&R) these statements is a requirement for C/C++ compilers.
Quote: |
Code: | if ((ptr!=NULL) && (ptr->son_ptr!=NULL))
<do something> |
would potentially lead to a problem when cheking the second condition if the pointer was NULL. I hope I explained well enough...
|
Yep, this is safe. This is a very common (and useful) construct. I use it (or similar constructs) all the time myself, and it's perfectly well-defined.
#168928 - elwing - Wed Jun 03, 2009 10:52 am
sverx wrote: |
and I was asking myself if writing
Code: | if ((ptr!=NULL) && (ptr->son_ptr!=NULL))
<do something> |
would potentially lead to a problem when cheking the second condition if the pointer was NULL. I hope I explained well enough...
Thanks everyone :) |
hum good example one where we could see that kind of example... I think I have already seen this kind of thing at work... not nice at all, but i guess it's a case were it is acceptable... and ansi C tell us the exact behaviour the compiler should have...
and to the reader what is done is pretty obvious... trough he might miss the trick to avoid an access violation if ptr is null
edit, doh too late...
#168929 - elwing - Wed Jun 03, 2009 10:54 am
kusma wrote: |
sverx wrote: | So, it seems to me that I understood that if I'm using the || operator then a "second" comparison will be made only if the "first" isn't TRUE, and the same with && operator and having the first part not FALSE (thus it's actually what Borland's Pascal called "short circuit evaluation") right? Everyone agree? |
Yes. This is a guarantee that K&R gives. Short circuiting (although I believe it's not called that by K&R) these statements is a requirement for C/C++ compilers. |
I have pasted the article from ansi C99 regarding this on the previous page
#168931 - kusma - Wed Jun 03, 2009 11:05 am
elwing wrote: |
kusma wrote: | Yes. This is a guarantee that K&R gives. Short circuiting (although I believe it's not called that by K&R) these statements is a requirement for C/C++ compilers. |
I have pasted the article from ansi C99 regarding this on the previous page |
Yeah, I just thought it would be good for the discussion to mention that it has been a guarantee all along since K&R, so it's a very safe assumption to make. Not everyone gets to play with C99-compliant compilers ;)
#168932 - gauauu - Wed Jun 03, 2009 3:06 pm
elwing wrote: |
not nice at all, but i guess it's a case were it is acceptable... |
Heh, short-circuiting to avoid dereferencing null pointers is one of the few places where I DO think it is both nice and acceptable.
And about getting fired for writing bad code -- I guess it depends on where you work. I've worked for 4 different places over the past 14 years. At 2 of them, bad code will get peer-reviewed and they'll just ask you to rewrite it better. At the other two, the worst that might happen is somebody might make fun of you if they HAPPENED to look at your code.
#168933 - elwing - Wed Jun 03, 2009 3:24 pm
personally I am working in a place where, as long as your code works, the other don't care... well, don't care much... and i just hate that, i'dd love more control...
#168934 - sgeos - Wed Jun 03, 2009 5:08 pm
gauauu wrote: |
if they HAPPENED to look at your code. |
Because something like the Microsoft Zune crash is what every company wants. Evidently it was an easy to spot stupid programming mistake. Three cheers for failing to implement code reviews.
#168935 - sajiimori - Wed Jun 03, 2009 6:16 pm
I use short circuiting all the time. I arrange conditional expressions so the cheapest/most-unlikely test comes first, so the expression will bail as quickly as possible.
I also don't believe that "uncommon" is the same thing as "bad", and I like short code. I don't write 12 lines when 2 will do. If the 2 lines need comments, then I write comments.
Guess I'm just weird like that! =)
#168936 - gmiller - Wed Jun 03, 2009 11:27 pm
Just remember that at the compiler level "most" compilers reverse your if logic to branch to the false code and fall into the true code. Of course your mileage may vary between compilers but they are trying to map what to type into assembly without introducing errors (pointer aliasing, etc ...) on their part and allow you to totally screw things up (as long as your syntax and type checking works) on your own.
The compiler standards dictate how the code should work not how the compiler should emit their code so there is room for differences as long as the result is the standard behavior.
#168938 - sajiimori - Thu Jun 04, 2009 3:30 am
I meant "a && b && c" as opposed to "if a then b else c".
I guess the compiler could rearrange the && expression, if it doesn't contain side-effects or extern calls. But in that case, I don't care much about the order, either...
#168945 - Miked0801 - Thu Jun 04, 2009 4:38 pm
Bah, what I was commenting on was using the prefix increment operator while counting on short-circuit if loops. Yes, it's standard. Yes, it should work in every case.
No, it is not intuitive nor readable if you have to go back and maintain it in the future, therefore it is a future source of headaches and bugs all because someone got cute. If you've got a strong reason for doing so, at least put a comment there calling out you are being cute for a reason.
On the null checks, I admit that I get a slightly uncomfortable every time I see:
Code: |
if(foo != null && foo->doSomething() == bleh)
|
just because I've been trained by wonderful compilers over the years not to trust them. I usually break that into 2 different if blocks - though that is much more whitespace and is almost certainly overkill.
And no, doing the prefix/if thing once won't get you fired. But that sort of code written over time will get you there quick. Keep it simple stupid unless you have a good reason not to - and then comment like crazy.
#168947 - kusma - Thu Jun 04, 2009 6:46 pm
Miked0801 wrote: |
just because I've been trained by wonderful compilers over the years not to trust them. |
Well, but to be able to get anything done, you absolutely HAVE to trust them. Whenever you find a breakage, find out why it breaks, and avoid that particular feature for that particular compiler. But for the love of god, verify that it's an actual compiler-bug. I WAY more often see programmers falsely believing they've found a compiler-bug than I see actual compiler-bugs... and I've been working on compilers and with other peoples alpha-quality compilers myself ;)
#168950 - Miked0801 - Thu Jun 04, 2009 11:21 pm
No worries, I don't go screaming compiler bug unless I am absolutely sure and have the proof in hand to back it. Claiming compiler bug otherwise is just a quick out that usually masks bad code.
#168962 - elyk1212 - Sat Jun 06, 2009 1:06 am
sgeos wrote: |
gauauu wrote: | if they HAPPENED to look at your code. |
Because something like the Microsoft Zune crash is what every company wants. Evidently it was an easy to spot stupid programming mistake. Three cheers for failing to implement code reviews. |
LOL, I worked at Freescale when that bug was spotted (It was actually FS code, I didn't work on that project though).
It was sad since, from my understanding, Freescale and MS seemed to have missed the bug, as it was example source handed over to MS...
AFAIK it was just example code on how to program the hardware, a template for MS to follow. But I didn't look into it much. Either way, many pairs of eyes viewed the code... or should have...
#168964 - sgeos - Sat Jun 06, 2009 10:56 am
elyk1212 wrote: |
AFAIK it was just example code on how to program the hardware, a template for MS to follow. But I didn't look into it much. Either way, many pairs of eyes viewed the code... or should have... |
So it was non-production code that slipped into the final product? When I was talking about this with some MS guys, they theorized that it was some code produced by a subcontractor that nobody looked at... it sounds like they were half right.
#168978 - elyk1212 - Sun Jun 07, 2009 9:38 pm
Yeah, from what I know, it was driver code handed off to MS, for the RTC. Usually when they come up with new hardware they'll come out with a programming manual, and example code how to program the hardware (the usual: avoid this bug, stick to this use case sort of thing).
I *think* this was one piece of such code, or so was the rumor at the office.