I have recently inherited an old project to make some optimization and add new features. In this project I have seen this type of condition all over the code:
if (int_variable)
instead of
if (int_variable > 0)
I have used the first option only with boolean type of variables.
Do you think the first option is a "correct" way to check if a number is positive?
negative numbers evaluate to true also,so you should go with if (int_variable > 0) to check if a number is positive.
No. The first option is a correct way to check if a number is non-zero.
Any non-zero value will be considered true, so your version with > is a bit sketchy if the variable truly is int, i.e. signed. For clarity I prefer to make that explicit in many cases, i.e. write
if (int_variable != 0)
This is perhaps a bit convoluted (basically computing a Boolean where one can be automatically inferred), I would never use if (bool_variable == true) for instance but I think the integer case makes the test clearer. Reading the two cases out loud works way better for the integer.
if (int_variable) has the same meaning as if (int_variable != 0).
This is not the same as if (int_variable > 0) unless you otherwise know that the value will never be negative.
When using an integer value as a truth value in C, zero yields false while any non-zero value yields true.
In your case, assuming int_variable is signed, (int_variable) is not equivalent to (int_variable > 0) since int_variable being negative will yield true and false, respectively.
So
if (int_variable) { … }
is not a correct way of checking whether int_variable is positive.
In C any expression which evaluates to integer 0 or a null pointer is considered false. Anything else is true.
So basically something like
int i = ...;
if ( i )
Test if i is 0. However, if i is negative, the condition will also be true, so this is no replacement for i > 0. Unless i is unsigned. Simply because they cannot be negative. But your compiler may warn about such constructs as they often show a wrong concept.
Coming to coding style, if ( i ) is bad style if you are really comparing to the value 0. You better compare explicitly: if ( i != 0 ). However, if i contains some boolean result, you should use a "speaking" name (e.g. isalpha('A') to use a ctypes.h function instead of a variable) and do not compare. Compare the readbility:
char ch = ...;
if ( isalpha(ch) )
if ( isalpha(ch) != 0 )
For the latter you have to think a second about the comparison - unnecessarily.
Related
I have this class which has a private bool member variable call positive. I want to check to see if both my class and the number I am adding to it are both positive so I wrote the expression
positive == (n > 0) //n is of type int
But for some reason when both are positive this evaluates to false. I then did a cout on positive and it has a value of 204! I though a boolean only holds 1 or 0. That would be why this is evaluating to false but why is that and how do I fix it? I am using Visual Studio 2013.
Just to clarify it should be == because I want to know if the sign is the same. So I want it to be true if both are negative or both are positive. I think I solved the problem which was that positive in one particular test case wasn't being initialized. But still why would a bool variable even if uninitialized contain a value larger and 1?
As per the standard, getting the value of an uninitialized variable is undefined behavior.
Since the actual size of a bool can be more than one bit, a bool variable containing rubbish can even hold bad values like 254. Welcome in the C++ hell!
And since (n > 0) evaluates to 1, 254 == 1 is false.
The bug is most likely due to the fact that positive never got a meaningful value since the object that contains it come into existence.
Search for a positive = something into your code and see if it is executed at least once before you use it.
Edited after Konrad comment:
The problem is most likely due to the fact that == is implemented between int-s and not bool-s relying on a bool-to-int promotion assuming the implementation of bool use 0 for false and 1 for true (and since && and || between int-s assume 0 for false and non-zero for true, bool-to-int promotion can be an identity).
This can be seen as a "compiler unfairness", but -since in the space of integer there is one false and bilions of trues- if operator==(bool,bool) was applied, there where more chance the uninitialized bug wold have been not discovered.
Treating bool as int in the arithmetic operations (not logic ones) makes bad-bool values to come out, thus revealing the bug.
Of course, since behind it there is an UB, it's all in an implementation choice. And it is int the freedom of each reading this to think I'm try to sell a bug as a feature.
Oh, you have a == where you should have an =.
The == doesn't assign, it checks for equality
Should be
bool positive = (n > 0) //n is of type int
bool generally holds only 1 or 0 after assignment. The only reason I can imagine you would see 204 in a bool is if the variable was uninitialized (so it had a junk value).
In source files which I am using in my project, there is a comparison between ssize_t and size_t variables:
ssize_t sst;
size_t st;
if(sst == st){...}
I would like to get rid of the warning:
warning: comparison between signed and unsigned integer expressions
But I am not sure, which variable should I cast to the other?
if((size_t)sst == st){...}
or
if(sst == (ssize_t)st){...}
What is safer, better, cleaner? Thanks
There is no one right answer to this question. There are several possible answers, depending on what you know a priori about the values that those variables may take on.
If you know that sst is non-negative, then you can safely cast sst to size_t, as this will not change the value (incidentally, this is what happens if you have no cast at all).
If sst might be negative but you know that st will never be larger than SSIZE_MAX, then you can safely cast st to ssize_t, as this will not change the value.
If sst might be negative, and st might be larger than SSIZE_MAX, then neither cast is correct; either one could change the value, resulting in an incorrect comparison. Instead, you would do the following if (sst >= 0 && (size_t)sst == st).
If you’re not absolutely certain that one of the first two situations applies, choose the third option as it is correct in all cases.
Either will work fine as long as both values fit in the positive representable range of ssize_t.
If either value doesn't, you could end up in trouble - check those cases before testing for equality:
if ((sst >= 0) && (st <= SSIZE_MAX) && (sst == (ssize_t)st))
{
...
}
(I'm sure the C++ people will recommend you avoid the C-style cast entirely - I have no doubt someone will comment or answer and let you know the right way to do that in C++.)
What happens if I compare two characters in this way:
if ('a' == 'b')
doSomething();
I'm really curious to know what the language (and the compiler) does when it finds a comparison like this. And, of course, if it is a correct way to do something, or if I have to use something like strcmp().
EDIT
Wait wait.
Since someone haven't understood what I really mean, I decided to explain in another way.
char x, y;
cout << "Put a character: ";
cin >> x;
cout << "Put another character: ";
cin >> y;
if (x == y)
doSomething();
Of course, in the if brackets you can replace == with any other comparison operator.
What really I want to know is: how the character are considered in C/C++? When the compiler compares two characters, how does it know that 'a' is different than 'b'? It refers to the ASCII table?
you can absolutely securely compare fundamental types by comparison operator ==
In C and C++, single character constants (and char variables) are integer values (in the mathematical sense, not in the sense of int values). The compiler compares them as integers when you use ==. You can also use the other integer comparison operators (<, <=, etc.) You can also add and subtract them. (For instance, a common idiom to change a digit character into its numerical value is c - '0'.)
For single chars, this form is correct. If both operands are known at compile time as in your example, then the condition can (and almost certainly will) be evaluated at compile time and not result in any code.
Note that a char ('a') is different from a single-character string ("a"). For the latter, comparison has a different meaning: it would compare the pointers rather than the characters.
Your processor would subtract both operands and if it's zero, zero condition bit is set, your values were the same.
For example: on arm machines you have the nzcv (negative, zero, carry, overflow) bits which tell you what happened.
Nothing will happen as a doesn't equal b.
If you question is just about is that the correct way, then the answer is yes.
First 'a' and 'b' are not strings, they are characters. The nuance is important because of its implications.
You can compare characters to characters just fine the same way you can compare integers to integers and floats with floats. It's usually not done because the outcome will always be the same. i.e. 'a' == 'b' will always be false.
If you're comparing strings, however, you'll have to use something like strcmp().
Compiler simply inserts an instruction for comparing two bytes for equality - a very efficient operation. Of course in your case 'a'=='b' is equivalent to a constant false.
The compiler will compare the numeric ASCII codes. So, 'a' is never equal to 'b'. But,
'a' < 'b' evaluates to true, since 'a' appears before 'b' in the ASCII table.
Of course, you want to use variables like
char myChr = 'a' ;
if( myChr == 'b' ) puts( "It's b" ) ;
Now you can start to think about "Yoda conditions", where you would do
if( 'b' == myChr ) puts( "It's a b" ) ;
so that in case you accidently typed one equals sign in the 2nd example:
if( 'b' = myChr ) puts( "It's a b" ) ;
that would raise a compiler error
Here is my code snippet:
int a;
if(a=8)
cout<<"Its right";
else
cout<<"Not at all";
getch();
return(0);
I'm getting the output Its right while I've not give any input there its just a assignment to the a=8.
**Borland Compiler** gives the following 2 warnings and executes the code.
1: Possible incorrect assignment (a=8)
2: 'a' is assigned a value that is never used.
When you write:
if(a=8)
You're assigning 8 to the variable a, and returning a, so you're effectively writing:
a = 8;
if(a)
This is non-zero, and hence treated as "true".
I (and the compiler) suspect you intended to write (note == instead of =):
if(a==8)
This is why you get the warnings. (Note that, in this case, a is still uninitialized, so the behavior is undefined. You will still get a warning, and may still return true...)
a = 8 assign 8 to a and returns the value of the assignment, that is 8. 8 is different from 0 and thus is considered true. the test apsses, and the program outputs "Its right".
you may have written if ( a == 8 ) which correctly tests the value of a without changing its value.
if(a=8)
implies assign a value of 8 to a and then use it to evaluate for the if statement. Since 8 is nonzero it essentially translates to TRUE (any value that is non-zero is true).
The first warning is because it's a frequent typo to write = in a condition test where you meant ==. The philosophy behind the warning is that it's a lesser burden for a programmer to rewrite if(a=b) to, say if((a=b)!=0) in the few cases he wants that, than to spend frustrating hours debugging the results if he mistakenly got an assignment instead of a comparison.
The second warning is just what it says: It looks like a mistake to have a local variable that you assign a value to but never use.
Since they are just warnings, you're free to ignore them if you think you know what you're doing. The compiler may even provide a way for you to turn them off.
Everyone else's answer is correct :)
if (a = 8) // Sets a to be 8 (and returns true so the if statement passes)
if (a == 8) // Check to see if a is equal to 8
I just want to add that I always (force of habit!) write if statements this way :
if (8 == a) {
Now, if I miss out one of the =, the compiler doesn't give me a warning, it gives me an error :)
You need a == (double equals). Single = is an assignment; when treated as an expression as you have done here, it evaluates to the value assigned, in this case 8. 0 is treated as False and anything else is True, so (a=8) == 8 == True.
I found this typo recently:
if (name.find('/' != string::npos))
Obviously the dev meant to type
if(name.find('/') != string::npos)
But I was amazed that to find that the error even compiles with -Wall -Werror (didnt try with -pedantic)
So, coffee quiz: does it evaluate to true or false?
'/' doesn't equal string::npos since npos is required to be negative, and none of the characters in the basic execution character set is allowed to be negative. Therefore, it's going to look for a value of 1 in the string (presumably a string anyway) represented by name. That's a pretty unusual value to have in a string, so it's usually not going to find it, which means it'll return std::string::npos, which will convert to true.
Edit: as Johannes pointed out, although the value assigned to npos must be negative 1 (as per 21.3/6) that's being assigned to a size_type, which must be unsigned, so the result won't be negative. This wouldn't normally make any real difference though -- the '/' would be compared to npos using unsigned arithmetic, so the only way they could have the same value would be if 1) '/' was encoded as -1 (not allowed as above) or char had the same range as size_type.
In theory, the standard allows char to have the same range as other integral types. In fact, quite a bit of I/O depends on EOF having a value that couldn't originate from the file, which basically translates to a requirement that char have a range that's smaller than int, not just smaller than or equal to (as the standard directly requires).
That does leave one loophole, though it's one that would generally be quite horrible: that char and short have the same range, size_type is the same as unsigned short, and int has a greater range than char/short. Giving char and short the same range wouldn't be all that horrible, but restricting size_type to the same range as short normally would be -- in a typical case, short is 16 bits, so it would restrict containers to 64K. That kind of restriction was problematic 20 years ago under MS-DOS; it simply wouldn't be accepted in most markets today.
It depends on if name starts with a char equal to 1.
You shouldn't be amazed it compiles, there's nothing wrong about it. '/' != std::string:npos evaluates to true, and the only overload of find that would work is the char c, size_t pos version, as bool can be converted to an integer 1.
So now we're looking for (char)1, and what that returns depends on the string. If it starts with (char)1, it returns 0 and that's false. In any other case, it returns a non-zero integer, or true.
'/' != string::npos evaluates to true. true is promoted to int (value = 1). find probably doesn't find a value of 1. if expression probably returns string::npos, which is typically -1, which is not zero, and is therefore true. My guess: true.
I'd say false, unless name contains a char with value 0x01.
I'm surprised the implicit cast from bool to char doesn't emit a warning... as far as I can tell, it'll return true unless name begins with '\001'.
It will evaluate to true if name contains a char == SOH
otherwise false
Others have posted the correct answer already: The result of the boolean expression should be 1 (a truth value), because '/' should have a value smaller than the unsigned string::npos (defined to be the largest value a size_t can hold). Because 1 is an integer, and because 1 can't possibly be an address, the compiler finds the only overload of string::find() it can call is the one with char c, size_t pos.
But that's not the end of the story. Try to change the boolean expression from '/' != string::npos to '/' == string::npos. Now the result of the expression is 0, again an integer. Because there is no overload for string::find() that takes an int, the compiler must cast 0 -- but to what? It can cast it to a char and it can cast it to a pointer. Both are valid choices, so that's an ambiguous call.
So there you go: your code changes from a valid warning-free function call to an ambiguous function call by changing an operator from != to ==.