if (variable) {

Go To Last Post
44 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I've always used "while" and "if" statements such as

 

while (1) {
  // just do stuff here, endlessly
}

and

if(appleSauce) {
    // if appleSauce is not zero then do some stuff here
}

without giving it much thought.

 

But a while back I read somewhere (somewhere I can't find now) that the "while" and "if" statement should have a logical test case to evaluate and not simply a value, and that the compiler was giving me a pass when I gave it only a value.  And instead, I should always give the "while" and "if" statement an actual test, as shown below:

while (1>0) {
  // just do stuff here, endlessly
}

or

if(appleSauce != 0) {
    // if appleSauce is not zero then do some stuff here
}

So what's the correct answer?  Is it OK to just use the value of a variable or constant with "while" and "if" because the compiler defaults to "is not equal to zero" when it isn't given an actual logical statement to evaluate?

 

thanks,

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

paul_n wrote:
I read somewhere (somewhere I can't find now) that the "while" and "if" statement should have a logical test case to evaluate and not simply a value

That's rubbish.

 

What goes inside the while or if is an expression - and a literal value or a single variable name are perfectly valid forms of expression.

 

paul_n wrote:
the compiler was giving me a pass when I gave it only a value

Not sure what that means?

 

paul_n wrote:
always give the "while" and "if" statement an actual test

Nonsense.

 

paul_n wrote:
So what's the correct answer? 

you were fine as you were

 

paul_n wrote:
Is it OK to just use the value of a variable or constant

Yes

 

paul_n wrote:
the compiler defaults to "is not equal to zero"

it's not a matter of "defaulting" - that's what the compiler always does.

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

well according to my K&R the if (expression) is evaluated, and if non-zero then execute the next substatement.  Since constant expressions are still expressions, that works fine.

 

Jim

 

 

(Possum Lodge oath) Quando omni flunkus, moritati.

"I thought growing old would take longer"

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

 

 

This would appear to be the relevant part from the C standard:

 

 

The only requirement for it to enter the statement block is that the expression evaluate to non 0.

 

The constant 1 is a non-0 expression:

 

 

The type is "int" from ...

 

 

 

Last Edited: Mon. Feb 8, 2021 - 03:03 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0


BTW

paul_n wrote:
and that the compiler was giving me a pass when I gave it only a value. 
Well rather than a compiler you might consider a linter. But even if you wind up all the verbosity in:

 

 

You still won't get a warning out of the compiler for:

 

int main(void)
{
    /* Replace with your application code */
    while (1) 
    {

because there is nothing wrong with t. It's not "giving a pass". It's just not wrong.

 

Actually talking of "linters" - you can try one out here:

 

https://www.gimpel.com/demo.html

 

something like:

 

So that's the worst it can complain about - the possible infinite loop you might not have intended - except we did.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It's really a matter of convention and programming style.

Some people for example will say to use

if (applesauce)

in the case where applesauce is a bool type

and to use

if (applesauce != 0)

in the case where applesauce is some other integer type

and to use

if (applesauce != NULL)

when applesauce is a pointer type,

but ultimately it's all the same result.

Just a matter of what you think makes the intention of the code clear.

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The examples you gave are merely chopped down conditionals, extremely simplistic, but completely valid. Conditionals are used to make decisions (from the most complex, to the simplest).

 

if (pressure  > 300 && rpm < 200 ){

   // sound the alarm in here

   // only when BOTH conditions are true

 

You've given the algebra version of  A = 27    ....valid algebra, but a boring final exam problem to solve for A (might trick some students!)

 

    // if appleSauce is not zero then do some stuff here

You DO have to be careful, since not all languages treat every non-zero as true and also zero as false (I'd have to go look it up)....falling into that trap can make for some interesting debugging.

 

Also, you have to not get tripped up:  if mydog  evaluates true, and also mycat evaluates true, it may unexpectedly fail the test of:  if (mydog == mycat), yet both are "true", which can cause some strange logical head-scratching faults. 

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

Last Edited: Mon. Feb 8, 2021 - 04:56 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks to all for your comments and insights. 

 

Paul

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Just to add a little obfuscation, here -

 

A logical test such as (x > 0) will always produce zero or the standard logical "not zero". Maybe the original author thought this would be somehow "safer" than (x). The only requirement is a simple one: you need to understand how logical tests are done.

 

If x is an integer, it can ONLY take on the discrete "perfect integer" values of {0,1,2,...} if unsigned or {...,-2,-1,0,1,2,...} if signed. There is no chance of being "almost but not quite zero". "1" is just as much "non-zero" as "99" is. Now, if you are testing a floating point value, you might, indeed, question how close to zero it might be. But, in my humble opinion, nobody in their right mind would use a floating point constant for the argument of a while() intended to be a perpetual loop, so we can pretty much discard that case. 

 

The important fact is that if() and while() simply expect an expression that is zero or not zero. It matters not one whit how you get to zero or not zero. If (1>0) somehow makes it more clear to you, then use it. The compiler will remove that test, since it is a constant at compile time and will replace it with its standard "not zero" value. Or you can use (1) which is as not-zero as you can get. Or, you can use (99) which is also as not-zero as you can get. Or, if you have boolean expressions defined, you can use (TRUE). What ever floats your boat! None of those is demonstrably "better" in any way, than the others.

 

Jim

 

Until Black Lives Matter, we do not have "All Lives Matter"!

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I believe visual basic used -1 & 0 , rather than 0 & 1 for equivalents true & false ( though use of numbers is strongly discouraged)

 

DOS and exit codes from applications generally use 0 to mean success and non-zero to mean failure of some type!

 

not a language per se, but a thinking trap, for the C shell:

NOTE: The logical values of true and false used by expressions are different from the values of true and false used by the conditional execution operators && and ||. In fact, the values are reversed: true is zero and false is any nonzero value.

 

An interesting mash-up to keep in your coat pocket

https://stackoverflow.com/questi....

 

None of this is really important, unless you are porting from one land to another (then maybe watch out).

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

Last Edited: Mon. Feb 8, 2021 - 05:36 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

paul_n wrote:
I've always used "while" and "if" statements such as

while (1) {
  // just do stuff here, endlessly
}

If you're looking for an alternative without "magic numbers", a common idiom is:

for(;;) {
  // just do stuff here, endlessly
}

https://en.wikipedia.org/wiki/Infinite_loop#Examples_of_intentional_infinite_loops

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I've always been uncomfortable with the concept that "false" is value 0x00 and "true" is any non-zero value, that is the accepted format in C and most other languages.  It is not so in assembler; where 0x00 can be a valid value within a specific range.  In asm it can be a value that is never ( or almost never) used which is selected to represent "false", for example 0xffff or a signature or quickly identifiable value like 0xBABE.

 

   In C and C++ I always use a format for a boolean that is self-documenting, for example :  if ( isDoorClosed == false) {closeDoor(); isDoorClosed = true; }     It doesn't fall into the realm of cute C tricks and notations, but it makes the code quick and easy to understand.

Last Edited: Mon. Feb 8, 2021 - 06:29 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Simonetta wrote:
that is the accepted format in C

It's not just "accepted format" - it is clearly defined by the language standard.

 

I'm pretty sure that it's because (virtually?) all machines have a hardware instruction to check if a value is zero or not.

 

EDIT 

 

Simonetta wrote:
if( isDoorClosed == false) ... makes the code quick and easy to understand.

I'm not sure that it does?

 

if( !isDoorClosed )  seems a more "natural" way to say it?

 

or even if( !doorIsClosed ) 

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
Last Edited: Mon. Feb 8, 2021 - 06:53 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

To be clear: the result of a relational expression is always (int)0 or (int)1 .

The casts are redundant.

(!x) == (!y) is 0 iff x or y is zero, but not both.

Also, (x==y)*z will work reliably.

The first factor will never be two.

Moderation in all things. -- ancient proverb

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

awneil wrote:
I'm pretty sure that it's because (virtually?) all machines have a hardware instruction to check if a value is zero or not.

 

Or possibly, that the result of a comparison or other arithmetic operation is zero or not?

 

Neil

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

To be clear: the result of a relational expression is always (int)0 or (int)1 .

Might be less misleading to say:

To be clear: the result of a C language relational expression is always (int)0 or (int)1 . 

 

If you've used other programming languages you're probably used to TRUE being equal to 1 and FALSE equal to zero. In VB True is in fact equal to -1.
https://www.vbforums.com/showthr...

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

awneil wrote:

If you're looking for an alternative without "magic numbers", a common idiom is:

for(;;) {
  // just do stuff here, endlessly
}

 

Thank you.  I wasn't aware that one could do something like that.  I'll use that next time.

 

Paul

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Wikipedia has interesting info about all this. Apparently in other languages most "string" are 'true' but the special string value "0" is 'false'. How confusing is that? I think we have it fairly easy in C.

 

EDIT: yup that "0" thing is in Perl in fact. (I only read that yesterday but could not remember today - sad!)

Last Edited: Tue. Feb 9, 2021 - 09:50 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Simonetta wrote:
In C and C++ I always use a format for a boolean that is self-documenting, for example :  if ( isDoorClosed == false) {closeDoor(); isDoorClosed = true; }     It doesn't fall into the realm of cute C tricks and notations, but it makes the code quick and easy to understand.

 

This is extremely, catastrophically difficult to read.

 

1. This is naturally readable

 

// No explicit comparison

if (isDoorClosed)
...

if (!isDoorClosed)
...

"Positivity" or "negativity" of the condition is immediately obvious.

 

2. This is worse but still bearable

 

// Explicit comparison, but always with `true`

if (isDoorClosed == true)
...

if (isDoorClosed != true)
...

The problem with this approach is that one has to keep track of two pieces of information - the comparison itself (`==` or `!=`) and the accompanying boolean value (`true` or `false`). By resolving to always use `true` one maintains some semblance of natural and obvious relationship: `==` is "positive`, while `!=` is "negative". This relationship is still concentrated in one spot: the comparison operator.

 

3. This is ultra-unreadable

 

// Explicit comparison with anything

if (isDoorClosed == false)
...

if (isDoorClosed != false)
...

when full freedom to choose both the comparison and the boolean constant is allowed, the reader has to keep track of both, and then has to calculate a XOR between the two in order to figure out whether the condition is "positive" or "negative".

 


 

The good Rule of Thumb to improve readability of logical conditions goes as follows:

 

1. Values that have boolean semantics should be checked without an explicit comparison. Use `!` operator if necessary.

2. All other values have to be compared explicitly. 

 

if (!isDoorClosed) // Good

if (isDoorClosed == false) // Bad

if (isalpha(c)) // Good

if (ptr != NULL) // Good

if (!strcmp(str1, str2)) // Bad

if (strcmp(str1, str2) == 0) // Good

 

Dessine-moi un mouton

Last Edited: Thu. Feb 11, 2021 - 08:54 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

AndreyT wrote:
This is extremely, catastrophically difficult to read.

+1 - see #13

 

I also find it helpful to name booleans so that the name reads as a statement of the state they represent; eg doorIsClosed.

 

Then logical tests read like natural language:

if( doorIsClosed )

 

"isDoorClosed" sounds like a question to me, rather than a statement - so it could be a good name for a function which determines the open/closed state of the door.

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Note there can be a slight unappreciated difference between:

if (isDoorClosed)    ...show door closed indicator lamp
if (isDoorClosed == true)  ...else if not, will sound alarm

The first applies to many values considered to be "true"  (say isDoorClosed had a value of 13)

The 2nd applies only to the one specific corresponding value of "true"

Say you were in a hurry & used both styles in the same program in different locations...you might wonder why the door alarm is sounding, yet the door closed indicator lamp shows that it is closed...but that's impossible, you say--I check both for the door being closed!!   The alarm should never go off if the indicator shows it is closed!

 

 

 

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

you can always use !! to convert any true to 1. ;)   (I both love and hate C)

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

you can always use !! to convert any true to 1. ;)   (I both love and hate C)

That's interesting...but is it really true (a fun time to use a pun)...what I'm saying, is would the compiler get "too smart" and just remove the double !!, making no effect? I wouldn't trust it & endup inspecting it to see what happened.

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

avrcandies wrote:
That's interesting...but is it really true (a fun time to use a pun)...what I'm saying, is would the compiler get "too smart" and just remove the double !!, making no effect? I wouldn't trust it & endup inspecting it to see what happened.

OK, I'll bite -- why would this "too smart" compiler that you cite pick this particular operator (or pair of operators) to ignore?

 

I suppose your ecad program is also too smart, and "removes" a double Schmitt trigger inverter gate stage?

 

So, you say it will not not remove two consecutive operators if they serve a useful purpose?  [a fun time to use an example]

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Nope, you'll see the same thing used across the Linux kernel code. It's kind of the standard way to convert <non-0>/0 into 1/0. I don't think the compiler can ignore it for the very reason that this must be the result. For example:

int n = !!46;

must result in n holding 1 not 46. (but this one it can compute at compile time). For example:

00000080 <main>:

int main(void)
{
    while (1) 
    {
        PORTB = !!46;
  80:	81 e0       	ldi	r24, 0x01	; 1
  82:	85 b9       	out	0x05, r24	; 5
  84:	fe cf       	rjmp	.-4      	; 0x82 <main+0x2>

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

avrcandies wrote:
The first applies to many (sic?) values considered to be "true" 

all values considered to be "true" - surely?

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

OK, I'll bite -- why would this "too smart" compiler that you cite pick this particular operator (or pair of operators) to ignore?

I'm asking a question, not making a statement--which way does it get treated.

 

It could potentially optimize wherever it might appear beneficial, based on pure logic--since that is certainly one aspect of logical optimization.  such as

(aa && bb) || (aa && !bb) is just aa

 

What happens if you have cat = dog + -1*frog ...you say it will do a lengthy multiply & add, or would it simply subtract frog (along with any consequences that might generate).   How much tidying up is applied can have large consequences.

You could have apple = 3 + apple -3  , what then--how much math optimization occurs?

   

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

Last Edited: Thu. Feb 11, 2021 - 04:49 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

all values considered to be "true" - surely?

if (isDoorClosed == true)    ...show door closed indicator lamp

Here, only one value applies for indicating the door is closed

if (isDoorClosed) ...show door closed indicator lamp

Here, many values apply for indicating the door is closed

 

would be more clear to add the

The first applies to the many values considered to be "true"

The 2nd applies only to the one specific corresponding value of "true"

 

 

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

Last Edited: Thu. Feb 11, 2021 - 04:38 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

avrcandies wrote:
What happens if you have ...

Obfuscate much?  I asked specific questions related to your specific muses.  Stick to those until the discussion is done.  How do you know?  Read the posting that caused your post that I am questioning.  I asked about

theusch wrote:
why would this "too smart" compiler that you cite pick this particular operator (or pair of operators) to ignore?

If you really care to continue after all the other "evidence" has been posted, please stick to resolving this particular clarification request.  In the divergence to a different example, of some sort, the original seems to be ignored, as are clawson and awneil explanations.

 

[edit]  In case y'all have not realized it, avrcandies will, always, get in the last post when there is anything but total agreement with the right-thinking opinion.  Thus, I'm editing here so that there won't be anything following.

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

Last Edited: Thu. Feb 11, 2021 - 05:50 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

avrcandies wrote:

if (isDoorClosed) ...show door closed indicator lamp

Here, many values apply for indicating the door is closed

I think it would be clearest to just say that all non-zero values will be taken as "true" in that case.

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

why would this "too smart" compiler that you cite pick this particular operator (or pair of operators) to ignore?

 pick this particular operator..I never implied it was picking one type over another.   

My post asked a question, not made a statement--which way does it get treated & was a reply to your question.

 

So, you say it will not not remove two consecutive operators if they serve a useful purpose?  [a fun time to use an example]

Why would it be particularly different than other possible optimization

(aa && bb) || (aa && !bb)  is just aa

apple = 3 + apple -3   as just apple

If that's what you wanted then without a doubt any other answer would be subject to additional validation.

 

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This is why C99 and C++ have the bool type—a bool variable can only ever be true or false, and assigning a non-bool value to a bool variable like b = x; is equivalent to b = !!x; (or to b = x != 0; if you prefer).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

avrcandies wrote:

It could potentially optimize wherever it might appear beneficial, based on pure logic--since that is certainly one aspect of logical optimization.  such as

(aa && bb) || (aa && !bb) is just aa

 

What happens if you have cat = dog + -1*frog ...you say it will do a lengthy multiply & add, or would it simply subtract frog (along with any consequences that might generate).   How much tidying up is applied can have large consequences.

You could have apple = 3 + apple -3  , what then--how much math optimization occurs?

 

The compiler can optimize/rearrange/discard/change anything in any way as long as it does not alter the observable behavior of the program mandated by the language specification. Observable behavior is basically defined as access to I/O features and to volatile variables. This is the so-called "as if" rule of C and C++ optimization. 

 

In general case the compiler is not free to "optimize away" a pair of `!!` operators, because `!!` is not a no-op in C. But if the compiler is sure that the original operand is already 0 or 1, then it can discard the `!!`.

 

Replacing `cat = dog + -1*frog` with `cat = dog - frog` and discarding `apple = 3 + apple - 3` - yes, that will happen in integer contexts, where full equivalence is preserved. In floating-point contexts - not necessarily.

Dessine-moi un mouton

Last Edited: Thu. Feb 11, 2021 - 05:19 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I think it would be clearest to just say that all non-zero values will be taken as "true" in that case.

Well, I more explicitly wanted to highlight that many values vs one value would satisfy.  All vs one, doesn't give the same impression.

all the drinks were consumed

many drinks were consumed

one drink was guzzled

I suppose I need a drink!

 

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

Last Edited: Thu. Feb 11, 2021 - 05:28 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 the compiler is not free to "optimize away" a pair of `!!` operators, because `!!` is not a no-op in C.

That is interesting & informative (pun)

 

so, then, what about  (aa && !!bb) || ( aa && !bb)  ..is !!bb forced to be left alone, or is the final result simplified to aa (which it truly is, logic-wise) ?   From what you say, it sounds like it must remain nonoptimized, as the original equation

 

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

avrcandies wrote:

so, then, what about  (aa && !!bb) || ( aa && !bb)  ..is !!bb forced to be left alone, or is the final result simplified to aa (which it truly is, logic-wise) ?   From what you say, it sounds like it must remain nonoptimized, as the original equation

 

It depends on the nature of `aa` and `bb`. C and C++ are not like functional languages. In C and C++ expressions are not pure and can have side-effects. So, in C and C++ expressions are evaluated not only for their results, but also for their side-effects.

 

Binary logical operators `&&` and `||` are strongly sequenced in C and C++ and require short-circuit evaluation. The language standard dictates the following abstract schedule for evaluating this expression:

 

1. Evaluate `aa`. If `aa` is zero, skip to step 3.

2. Evaluate `!!bb`. If `!!bb` is 1 - stop. The final result is 1.

3. Evaluate `aa`. If `aa` is zero - stop. The final result is 0.

4. Evaluate `!bb`. The value of `!bb` is the final result.

 

Now, if `aa` and `bb` are simple variables or constants (more formally: if these are expressions without side-effects), then there's no real need to literally follow this schedule. And yes, the compiler is free to optimize the whole thing to a mere `aa`. Any modern compiler is smart enough to do exactly that.

 

But if `aa` and `bb` stand for more complex expressions with side-effects, then the compiler will have to follow the above schedule, more-or-less. For example, for this

 

int a = 0, b = 1;
int c = (++a && !!--b) || (++a && !--b);

 

the compiler will have to perform the "full" evaluation because we are supposed to end up with `a == 2`, `b == -1` and `c == 0`.

 

Of course, the compiler can additionally analyze the nature of these side-effects and optimize the evaluation in some other way. But it won't be a simple `aa`.

 

 

Dessine-moi un mouton

Last Edited: Thu. Feb 11, 2021 - 06:16 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Of course, one can have even more redundancy:

 

if (DOORISCLOSED)
{
    ...
}

if (DOORISOPEN)
{
    ...
}

where both apparent variables are macros that perform the actual open/closed test...

 

Neil (no, I don't recommend it!)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Now, if `aa` and `bb` are simple variables or constants (more formally: if these are expressions without side-effects), then there's no real need to literally follow this schedule. And yes, the compiler is free to optimize the whole thing to a mere `aa`. Any modern compiler is smart enough to do exactly that.

 Theusch seemed to have a great anguish with some of those smart compiler thoughts.

 

Your explanation is really interesting & informative!! 

 OK, then I'll go back to my original question about !! cancelling. Using the integer variable cat,  is !!cat replaced with cat (noting your parts highlighted above), meaning the double !! is  gotten rid of?  OR is there some side effect it sees (what?) that prevents it?  Or is !! in itself a "special entity" (and not considered two separate "!" together), so treated as a special case?  

 

Oh maybe you sort of answered this, though not sure how it correlates to the parts just highlighted:

In general case the compiler is not free to "optimize away" a pair of `!!` operators, because `!!` is not a no-op in C. 

 

 

 

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

Last Edited: Thu. Feb 11, 2021 - 07:19 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

avrcandies wrote:

 OK, then I'll go back to my original question about !! cancelling. Using the integer variable cat,  is !!cat replaced with cat (noting your parts highlighted above), meaning the double !! is  gotten rid of?  OR is there some side effect it sees (what?) that prevents it?  Or is !! in itself a "special entity" (and not considered two separate "!" together), so treated as a special case?  

 

No, in general case `!!` cannot be discarded, as I already stated above. 

 

Function `sin(x)` in standard library has no side effects. That does not mean that `sin(x)` can be replaced with mere `x`. The compiler still has to produce the proper result, i.e the sine value.

 

The same is true for `!!`. The `!!` combination has to "normalize" the value to 0 or 1. The compiler still has to do that.

 

And I'm not entirely correct when I say that without side effects `(aa && bb) || (aa && !bb)` can be optimized to a mere `aa`. This expression is still required to produce 0 or 1 result. Which means that in absence of side-effects it can be optimized to a mere `!!aa` or `aa != 0`. This would be correct.

 

For example, here's optimized GCC x86 code for 

 

#include <stdlib.h>

int main(void)
{
  int a = rand(), b = rand() + rand();
  int c = (a && b) || (a && !b);
  return c;
}
main:
        push    rbx
        call    rand      ; This is `rand()` call for `a`
        mov     ebx, eax  ; This is `a` stored in `ebx`
        call    rand      ; These are two `rand()` calls for `b`, but `b` itself has been eliminated
        call    rand
        xor     eax, eax  ; Forming `!!a`
        test    ebx, ebx  ; Forming `!!a`
        pop     rbx
        setne   al        ; Forming `!!a`
        ret

As you can see, the whole expression got reduced to a mere 

 

xor eax, eax
test ebx, ebx
setne al

This is `!!a`.

 

P.S. The compiler is still forced to make all three calls to `rand()` since rand has side effects the compiler does not want to lose.

Dessine-moi un mouton

Last Edited: Thu. Feb 11, 2021 - 07:39 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks --good explanation, though there are plenty of nuggets to think about!!  

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

avrcandies wrote:
 Theusch seemed to have a great anguish with some of those smart compiler thoughts.

No, as has been pointed out over and over:

AndreyT wrote:
No, in general case `!!` cannot be discarded, as I already stated above. 

So don't try to put words in my mouth just because, yet again, you will pick at some semi-related tangent.  Now I've left it for your famous last words.  Can you resist?  I think not.  And then the moderators will come and chastise me for pointing out that the Emperor has no clothes.  Harrumph.

https://www.youtube.com/watch?v=...

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

theusch wrote:
And then the moderators will come and chastise me for pointing out that the Emperor has no clothes.  Harrumph.

 

I think Both you and avrcandies need to take your bickering to a PM and not in threads.

 

 

From teh OP:

paul_n wrote:
Is it OK to just use the value of a variable or constant with "while" and "if"

 

I do it all the time.  The whole purpose of a WHILE, or an IF is to EVALUATE.......  and when the components in the statement meet the requirements of a WHILE, or an IF  the micro will perform a task.

 

 

Jim

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

jgmdesign wrote:

I think Both you and avrcandies need to take your bickering to a PM and not in threads.

 

See?  I can't win.  Review all the "bickering", Jim, and tell me where I went astray.  Are there any posts of mine without the truth?  Sheesh, again.  This goes on and on.  I call avrcandies out a few times, and he gets better for a month or two.  But then the Grand Pronouncements come out again, with the certainty of ex cathedra.  But I'm the bad guy.  I ain't bickerin'; I'm sayin'.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Moderation is about trying to persuade two supposedly grown adult men to stop bickering like two five year olds in the playground. Sadly this does not always seem to work :-(