PDA

View Full Version : C Programming Code Snippet




cybrscot
Apr 4, 2011, 10:41 AM
I'm trying to figure out what's wrong with this code snippet.

while (done = true)
done = ! done;


I'm not sure what to make of this one? is it just written wrong? Or does it just not do anything?? ?? I think true is being assigned to done, then ! done is being assigned to done. So now done holds the value ! done and gets tested at the top again....argh. Not sure here.

Or is the error that it should be (done == true)?? Can an assignment be used as an expression? Is that the error?



lee1210
Apr 4, 2011, 10:50 AM
done = true assigns the value of true to done, and evaluates to true.
done == true evaluates to true if done contains the same thing that true does, or false otherwise.

-Lee

KnightWRX
Apr 4, 2011, 10:50 AM
What is it you expect the code to do and what is it doing instead ? Have you compiled and run this code ? If you did, you'd instantly know what is wrong.

cybrscot
Apr 4, 2011, 10:57 AM
done = true assigns the value of true to done, and evaluates to true.
done == true evaluates to true if done contains the same thing that true does, or false otherwise.

-Lee


Thanks Lee, yeah I got that, but what's wrong with the code snippet? This is an exercise problem at the end of Chapter 7 in my "Learn C on the Mac" book. They're asking what's wrong with the fragment? It doesn't make sense to me, it seems like it will run forever, as the body assigns ! done to done, basically the opposite of it's previous value, then when done (which now contains ! done) gets tested, it has true assigned to it, then done (containing true) has ! done assigned to it again. ....I guess, is this also an infinite repeating loop?

dejo
Apr 4, 2011, 11:02 AM
They're asking what's wrong with the fragment? It doesn't make sense to me, it seems like it will run forever...
Perhaps that is what is wrong with the fragment... :)

lee1210
Apr 4, 2011, 11:08 AM
When asking "what's wrong?" you sort of need to know what it SHOULD do. If this should exit after 0/1 iterations, then running infinitely would be a problem. If it is supposed to constantly switch "done" from one state to another forever, it is working properly.

-Lee

cybrscot
Apr 4, 2011, 11:24 AM
When asking "what's wrong?" you sort of need to know what it SHOULD do. If this should exit after 0/1 iterations, then running infinitely would be a problem. If it is supposed to constantly switch "done" from one state to another forever, it is working properly.

-Lee

Yeah, who knows what it's supposed to do. At the top of the page it just says "What's wrong with each of the following code fragments", then has 8 different sets of code fragments. Some of them have syntax errors, this one appeared to be syntax error free, but I can only assume that it's looping forever is the problem, just wanted to get another pair of eyes on it. A couple of the previous ones were also infinite loops. I guess the reader is supposed to walk through these examples, see that they are infinite loops (although at first glance they don't appear to be) and assume that it's not optimal code for a loop. While there are better ways to write a loop if you intend to write one.

Thanks guys.

balamw
Apr 4, 2011, 04:45 PM
Some of them have syntax errors, this one appeared to be syntax error free

Confusing assignment and comparison operators is a syntax error. Sure it'll compile, but it's clearly not what was intended.

You have to be careful with a few aspects of this in C.
There is no proper Boolean type.
true/false are not specified by default. Assignment returns the right hand side of the assignment.


So if the rest of the code looked like:

int true = 0;
int done = 1;
while (done = true)
done = ! done;

The code would loop exactly no times.

B

admanimal
Apr 4, 2011, 05:04 PM
Confusing assignment and comparison operators is a syntax error. Sure it'll compile, but it's clearly not what was intended.



You have just described exactly why this is a semantic error and not a syntax error. Syntax errors are caught by the compiler. Semantic (i.e. logic) errors usually mean that the code runs but is not doing what you intend it to do. Granted the line is a bit fuzzy here since the logic error is clearly caused by an unintentional misuse of otherwise correct syntax.

balamw
Apr 4, 2011, 05:43 PM
Granted the line is a bit fuzzy here since the logic error is clearly caused by an unintentional misuse of otherwise correct syntax.

Sorry, I made it worse by deleting a paragraph. The gist of it was:

If C actually defined a proper Boolean type this would be more likely to actually be caught by the compiler.

(NOTE: The reason I deleted it is if both done and true were good Boolean variables rather than constants and assignment still returned the right hand side, the code would be OK again, but would still be a null or infinite loop depending on the value of true).

B

subsonix
Apr 4, 2011, 09:02 PM
C99 introduced stdbool.h, which defines a boolean type and true, false constants. In the end though, this is still an integer type.

Would be interesting to know if there are a language that actually has boolean type, where:

if(a)

is not the same as:

if(a == true)

lee1210
Apr 4, 2011, 09:31 PM
C99 introduced stdbool.h, which defines a boolean type and true, false constants. In the end though, this is still an integer type.

Would be interesting to know if there are a language that actually has boolean type, where:

if(a)

is not the same as:

if(a == true)

Fortran has a Boolean type. The Boolean literal for true is .true. and equivalence was only .eq. prior to fortran 90 when == was added. So the first statement, assuming a is boolean, is legal. The second isn't valid at all before fortran 90, and after fortran 90 I'm pretty sure you could declare true as a Boolean variable and set it to .false., yielding the opposite result of the first statement.

-Lee

SidBala
Apr 4, 2011, 10:20 PM
Isn't that an infinite loop?

subsonix
Apr 4, 2011, 10:50 PM
I guess I'm confusing things a bit here, if a is declared as: int a = 10;

Then the first statement evaluates to true, since in C true is anything non zero.
Yet: true is defined as 1. meaning the second statement is false given the value of a. So maybe any value that is not zero should pass that condition as well, given that any non zero values is supposed to be true. Or perhaps it should be an error disallowing comparisons between ints and bools.

jiminaus
Apr 5, 2011, 03:17 AM
I guess I'm confusing things a bit here, if a is declared as: int a = 10;

Then the first statement evaluates to true, since in C true is anything non zero.
Yet: true is defined as 1. meaning the second statement is false given the value of a. So maybe any value that is not zero should pass that condition as well, given that any non zero values is supposed to be true. Or perhaps it should be an error disallowing comparisons between ints and bools.

If the hypothetical language allowed implicit coercion from its integer type to its boolean type such that a non-zero integer is coerced to boolean true and therefore the code if (a) is valid, I would hope the same logic work prevale in the code if (a == true). That is a would be coerced to boolean true resulting in a boolean comparison. And not that boolean true would be coerced to integer 1 resulting is a dubious integer comparison.

But I'm sure one could find a language that did behave as in the later case. That's one of the reasons I liked coding in Ada in my last major project. Ada has no (or a least very limited) implicit coercion. If you wanted to code if (a == true) in Ada where a is an integer, you'd need to explicitly typecast one to the other to make your intent clear.

balamw
Apr 5, 2011, 08:20 AM
I'm pretty sure you could declare true as a Boolean variable and set it to .false., yielding the opposite result of the first statement.

And that's why context is critical.

Without stdbool, true is just a variable that could be defined as anything, including zero. (larswik just posted a Pascal thread where he effectively implicitly defined true as zero.) For all we know it's a float or char *.


Then the first statement evaluates to true, since in C true is anything non zero.

"a = true" will evaluate to the value of true, but if true has the value 0 (i.e. not using stdbool or locally overriding it) this will be interpreted as a logical false. (C has this nice behavior that allows stuff like "a = (b = 10);" to work since "b = 10" evaluates to 10.)

If the hypothetical language allowed implicit coercion from its integer type to its boolean type such that a non-zero integer is coerced to boolean true and therefore the code if (a) is valid, I would hope the same logic work prevale in the code if (a == true). That is a would be coerced to boolean true resulting in a boolean comparison. And not that boolean true would be coerced to integer 1 resulting is a dubious integer comparison.

And that's basically why the paragraph I deleted in the earlier post was deleted. It was getting a bit hypothetical and far above where I think cybrscot is.

Ultimately, the code snippet in question should be avoided for a multitude of reasons.

I usually err on the side of accepting that C doesn't have a boolean type and would write "while (done)" [or preferably "while (!done)" if I intended a loop :p] instead of "while (done == true)" and I would avoid putting "work" in the loop condition as we saw many examples of in cybrscot's for loop thread from the KN King book. You can interpret the original code snippet as:

while (true) {
done = true;
done = ! done;
}

It then becomes clear that its behavior only depends on the value of true.

B

subsonix
Apr 5, 2011, 09:05 AM
"a = true" will evaluate to the value of true, but if true has the value 0 (i.e. not using stdbool or locally overriding it) this will be interpreted as a logical false. (C has this nice behavior that allows stuff like "a = (b = 10);" to work since "b = 10" evaluates to 10.)


Yes but I was referring to the second case: if(a == true) and using the standard C definition of true in stdbool. It will evaluate to false for any values of 'a' but 1 (on mac OS at least). Basically, to get the statement working in a logic sense you would need something like: if( (a == 10) == true ) which is a bit weird. But given that 'a' is an integer, it's not that weird compared to asking if 'a' is true, since it can hold 2^32 different values.

IMO you shouldn't use stdbool 'true' on anything not declared as bool. This is an error in for example Java, and for good reasons.


I usually err on the side of accepting that C doesn't have a boolean type and would write "while (done)" [or preferably "while (!done)" if I intended a loop :p] instead of "while (done == true)"


Except if 'done' is declared as a bool, which makes sense unless your accepting more states than 2, like half-done and so on.:p

balamw
Apr 5, 2011, 09:34 AM
Except if 'done' is declared as a bool, which makes sense unless your accepting more states than 2, like half-done and so on.:p
I thought I was being clear that I was advocating accepting that done is an int in C and NOT using stdbool. (Apparently I wasn't being as clear as I thought ;).).

B

subsonix
Apr 5, 2011, 09:37 AM
I thought I was being clear that I was advocating accepting that done is an int in C and NOT using stdbool. (Apparently I wasn't being as clear as I thought ;).).

B

Well, if you try this:


bool test = 10;
printf("%d\n", test);


It prints 1. So, if you are going to use true/false in a program I think stdbool makes sense.

balamw
Apr 5, 2011, 09:56 AM
Well, if you try this:


bool test = 10;
printf("%d\n", test);


It prints 1. So, if you are going to use true/false in a program I think stdbool makes sense.

Ick! I know that works, but it exactly the kind of mixed message I'm seeking to avoid.

If you use stdbool you should strive to use only true/false as values for bool variables, not even (1/0). (As other languages with a real strong Boolean would force you to). If you want to use the looser, standard C behavior where false is zero and true is anything but, don't use stdbool and accept that true and false are ints.

At least do:


#include <stdbool.h>
bool test = (10 != 0);
printf("%d\n", test);


However that's just MHO.

B

subsonix
Apr 5, 2011, 10:05 AM
Ick! I know that works, but it exactly the kind of mixed message I'm seeking to avoid.


It's there just to demonstrate that it's not the same as declaring 'done' as an int. You would not do that in reality but instead: bool done = true;

Thus true/false tests will always work for 'done', unlike if 'done' was an int where only one value out of all 2^32 will evaluate to true.

balamw
Apr 5, 2011, 10:28 AM
Thus true/false tests will always work for 'done', unlike if 'done' was an int where only one value out of all 2^32 will evaluate to true.

Chickens and eggs. It only becomes an issue when you try to mix bool and int. So don't. (Again, just MHO).

If you don't use stdbool true/false tests (i.e. if statements, ternary statements, etc...) will always work for an int and there are 2^32-1 trues and one false.

You could replicate the behavior you see using bool without stdbool using a ternary statement in the printf. "done?1:0;".

B

subsonix
Apr 5, 2011, 10:35 AM
Chickens and eggs. It only becomes an issue when you try to mix bool and int. So don't. (Again, just MHO).


Well that is what I'm saying.


If you don't use stdbool true/false tests (i.e. if statements, ternary statements, etc...) will always work for an int and there are 2^32-1 trues and one false.


Again, in the context here what we are talking about is evaluations of this test:

if(a == true)

Where 'a' is in an int, it's only 1 value that is true, not all 32^2 values except zero.

I know that you are referring to:


if(a)
if(!a)


And so on, but..

balamw
Apr 5, 2011, 11:10 AM
I know we're not disagreeing, but I think it is a point worth discussion.

The problem IMHO is that given only the snippet of code in the first post, we don't know if stdbool.h is included or not so if true is defined as we might expect or not.

Generally, a == true is superfluous so don't use that form. If a is an int, you need a to be the one out of 2^32 values defined by true which is probably not the behavior you want. If a is a bool then it is already either true or false so what is the point of the comparison?

Try this one:

#include <stdio.h>
#include <stdbool.h>

int main(void)
{int a=10;

if(a==true) printf("a is true!\n!");
else printf("a is false!\n");

if((bool)a==true) printf("a is true!\n!");
else printf("a is false!\n");

return 0;
}


Bad juju, but again that's just MHO.

B

KnightWRX
Apr 5, 2011, 11:14 AM
Generally, a == true is superfluous so don't use that form. If a is an int, you need a to be the one out of 2^32 values defined by true which is probably not the behavior you want. If a is a bool then it is already either true or false so what is the point of the comparison?


The point was to use an assignment operator instead of a comparison operator to create an infinite loop so that the reader could identify the operator used in the loop's condition as the fault of the code snippet.

Remember guys, these are book exercises with a precise goal. The snippets might not make sense in a real world application, they are purely academic validations.

balamw
Apr 5, 2011, 11:55 AM
The point was to use an assignment operator instead of a comparison operator to create an infinite loop so that the reader could identify the operator used in the loop's condition as the fault of the code snippet.

I think we all agree that the author's intent was to flag the assignment instead of comparison in the loop condition, and you can check that by looking at the answers in the back of the book. :p

He writes:

This is probably the most common mistake made by C programmers. The assignment operator (=) is used instead of the logical equality operator (==). Since the assignment operator is perfectly legal inside an expression, the compiler won't find this error. This is an annoying error you'll encounter again and again! Consider using 20 == i instead of i == 20.

(Thanks Amazon!)

Without additional context, we don't know if it's an infinite loop or a no op loop. (Depends mainly on how "true" is defined).

Plus, the suggested trick of reversing the operands wouldn't necessarily help here as we don't know if true is declared as const, and it certainly isn't a literal. (However, if stdbool was included true = done would get the compiler to scream).

B

cybrscot
Apr 5, 2011, 12:55 PM
I think we all agree that the author's intent was to flag the assignment instead of comparison in the loop condition, and you can check that by looking at the answers in the back of the book. :p
B

Haha, I didn't even know the answers were in the back of the book! I wasn't expecting that since my other book doesn't have answers in it! Duh!!!

Thanks, that'll help some when I get stuck!

Sorry I didn't know they were there!

ender land
Apr 5, 2011, 02:14 PM
ugh, I wish I had a dollar every time I've seen or made an error related to checking equality :(

i've been programming a while now and STILL make those..

dejo
Apr 5, 2011, 02:16 PM
I still kinda like PL/SQL's assignment operator: :=