In some code i found the following line:
CPPUNIT_ASSERT(1, val.getBytefield().size());
Does this really compare the two parameters for equality? Normally, i would expect this comparison with CPPUNIT_ASSERT_EQUAL:
CPPUNIT_ASSERT_EQUAL(1, val.getBytefield().size());
The test compiles and the assertion works in case 1, but not in case 2. Where is the difference?
This just looks like broken code to me, probably the result of some refactoring or other editing that was done.
The CPPUNIT_ASSERT macro takes a single argument—a condition expression—and asserts that that condition is true (i.e., fails if it is false).
This code is attempting to pass two arguments, but rather than functioning as an argument delimiter here, the comma is actually working as the (somewhat obscure) comma operator. The comma operator evaluates its first operand, discards the result, and then evaluates to the result of the second operand. Therefore, the initial 1 is an irrelevant no-op. The code is equivalent to:
CPPUNIT_ASSERT(val.getBytefield().size());
which means that it's asserting that the byte field has a non-zero size.
Obviously, this is different from your second snippet of code:
CPPUNIT_ASSERT_EQUAL(1, val.getBytefield().size());
which asserts that the byte field's size is exactly equal to 1.
It seems like you are using a compiler has an extension, which accepts 2 parameters to a single argument macro. I guess it's MSVC, see this
Hence, the macro will check if the first argument is true or not, in your case, it's 1, which is contextual converted to the bool value true, by this expansion
#define CPPUNIT_ASSERT(C) \
( CPPUNIT_NS::Asserter::failIf( !(C), \
CPPUNIT_NS::Message( "assertion failed", \
"Expression: " #C), \
CPPUNIT_SOURCELINE() ) )
You can double check my statement by change:
CPPUNIT_ASSERT(1, val.getBytefield().size());
with:
CPPUNIT_ASSERT(1000, val.getBytefield().size());
CPPUNIT_ASSERT_EQUAL(1, val.getBytefield().size());
From my experiment, .size() will likely return a std::size_t. From the definition of CPPUNIT_ASSERT_EQUAL:
#define CPPUNIT_ASSERT_EQUAL(expected,actual) \
(assertEquals((expected), \
(actual), \
CPPUNIT_SOURCELINE(), \
"" ) )
and assertEquals:
template<class T>
void assertEquals ( const T & expected,
const T & actual,
SourceLine sourceLine,
const std::string & message
)
Because type of 1 (int) and return type of .size() (std::size_t) is different, then no matching function can be found, the compiler can not compile your code.
I think this is the solution:
CPPUNIT_ASSERT(1 == val.getBytefield().size());
CPPUNIT_ASSERT_EQUAL(std::size_t(1), val.getBytefield().size());
Related
In Visual Studio the assert macro is defined like this:
#define assert(expression) (void)( \
(!!(expression)) || \
(_wassert(_CRT_WIDE(#expression), _CRT_WIDE(__FILE__), (unsigned)(__LINE__)), 0) \
)
I get that the right part after || is only evaluated if the left expression is false, and throws an exception.
I have 3 questions:
The !! double negation is to convert the 'expression' type to bool, right? What would happen if they were left out? The 'expression would be implicitly converted to bool when it's logically or'ed with another expression, right? In:
float() || /* Call function that throws*/;
The float() is converted to bool type anyway?
2.After the || operator we have:
( /* call function that throws */ , 0 )
The comma is a sequence point, so first the function is called and then this expression is evaluated as 0. If the function call didn't terminate the program then the expression would simply be:
!!(expression)) || 0
What's the point of that 0 after the comma? If if weren't there, then the expression would be:
!!(expression)) || / * call function that throws */
Which is the same thing, right?
And finally the (void), I'm wondering what this is for.
Let's break down the code:
#define assert(expression) (void)( \
(!!(expression)) || \
(_wassert(_CRT_WIDE(#expression), _CRT_WIDE(__FILE__), (unsigned)(__LINE__)), 0) \
)
The (void) is to squelch the compiler warning that the expression result is unused. And also ensures that the assert is not accidentally used as part of a larger expression.
The !! part of the !!(expression) is to ensure that the expression evaluates to false or true.
But mischievous C++ code could have overridden operator! and cause a bit of chaos here.
Why C-style cast, and not static_cast<bool>? I suspect the same header file is used to support C and C++, and possibly C++/CLI as well. (If so, could be justification to use static_cast<bool> for C++, and (bool) for C in two language specific macros.)
If the expression object has an operator bool conversion, it will be used by the !!. (But would also have been used by (bool)(expression).)
Regardless, the observation that the !! is unnecessary seems correct to me. Expressions in C++ that are truthy (non-zero) or falsy (zero) is part-and-parcel to the language.
The (x(), 0) comma operator is used because the x (in this case the _wassert) returns a void. Can't do an a || b if the b is void, so the trickery just makes it so the void is called, and the expression results in an int. It does not matter that it is 0.
The _wassert does not throw. It may abort with exit code 3. It may break into the debugger.
It may be ignored and continue. And with the assert having been violated there could be a broken axle consequences, or the code may have some defensive programming to handled the assert violation.
Since the assert function-like macro was written as an expression, it neatly avoids the problem of the "dangling if macro" (had an if (!(expression)) ... construct been used), and is an expression rather than a statement.
I cannot figure out what the difference between the following pieces of code is:
int t = __double2int_rd(pos.x/params.cellSize.x*2.0)&1;
if( t ==0) {...}
and
if(__double2int_rd(pos.x/params.cellSize.x*2.0)&1 == 0) {...}
The second option never returns true, while the first behaves as expected.
Does anyone have any ideas?
The second expression first evaluates (1==0) whose result is always false. Then ANDs it with the result of the function __double2int_rd.
Therefore it actually evaluates:
if(__double2int_rd(pos.x/params.cellSize.x*2.0) & 0)
Which would always be false.
The equivalent of the first expression would be:
if((__double2int_rd(pos.x/params.cellSize.x*2.0) & 1) == 0)
Mind the brackets.
Its a good programming practice to add brackets if you are not sure about the order of evaluation of expressions.
When I define this macro:
#define SQR(x) x*x
Let's say this expression:
SQR(a+b)
This expression will be replaced by the macro and looks like:
a+b*a+b
But, if I put a ++ operator before the expression:
++SQR(a+b)
What the expression looks like now? Is this ++ placed befor every part of SQR paramete? Like this:
++a+b*++a+b
Here I give a simple program:
#define SQR(x) x*x
int a, k = 3;
a = SQR(k+1) // 7
a = ++SQR(k+1) //9
When defining macros, you basically always want to put the macro parameters in parens to prevent the kind of weird behaviour in your first example, and put the result in parens so it can be safely used without side-effects. Using
#define SQR(x) ((x)*(x))
makes SQR(a+b) expand to ((a+b)*(a+b)) which would be mathematically correct (unlike a+b*a+b, which is equal to ab+a+b).
Putting things before or after a macro won't enter the macro. So ++SQR(x) becomes ++x*x in your example.
Note the following:
int a=3, b=1;
SQR(a+b) // ==> a+b*a+b = 3+1*3+1 = 7
++SQR(a+b) // ==> ++a+b*a+b ==> 4 + 1*4 + 1 = 9
// since preincrement will affect the value of a before it is read.
You're seeing the ++SQR(a+b) appear to increment by 2 since the preincrement kicks in before a i read either time, i.e. a increments, then is used twice and so the result is 2 higher than expected.
NOTE As #JonathanLeffler points out, the latter call invokes undefined behaviour; the evaluation is not guaranteed to happen left-to-right. It might produce different results on different compilers/OSes, and thus should never be relied on.
For C++ the right way to define this macro is to not use a macro, but instead use:
template<typename T> static T SQR( T a ) { return a*a; }
This will get right some horrible cases that the macro gets wrong:
For example:
SQR(++a);
with the function form ++a will be evaluated once. In the macro form you get undefined behaviour as you modify and read a value multiple times between sequence points (at least for C++)
A macro definition just replaces the code,hence it is generally preferable to put into parenthesis otherwise the code may replaced in a way you don't want.
Hence if you define it as :
#define SQR(x) ((x)*(x))
then
++SQR(a+b) = ++((a+b)*(a+b))
In your example, ++SQR(a+b) should be expanded as ++a+b*a+b.
So, if a == 3 and b == 1 you will get the answer 9 if the compiler evaluates it from left to right.
But your statement ++SQR(3+1) is not correct because it will be expanded as ++3+1*3+1 where ++3 is invalid.
In your preprocessor it evaluates to ++a+b*a+b. The right way is put brackets around each term and around the whole thing, like:
#define SQR(x) ((x)*(x))
I have just installed the Windows SDK v7.1 (MSVC 10.0) and running my code through (almost) full warning level (W3, default for qmake's CONFIG += warn_on) and am surprised about warning C4800: 'type' : forcing value to bool 'true' or 'false' (performance warning)
In the following code, stream is an std::istream and token is a std::string.
// in some function returning bool
return (stream >> token) // triggers warning c4800:
// '(void *)': forcing value to bool 'true' or 'false' (performance warning)`
// somewhere else
if( stream >> token ) // does not trigger warning c4800
What is going on here? I don't even get why the warning is triggered in the first place. I thought the first bit of code already returned a bool anyways.
I understand this is nitpicking and the warning shouldn't even exist, but it's the only one in my code between MSVC's /W3 and gcc's -Wall -pedantic, so I'd like to know :)
SMALL UPDATE: I understand that the warning is designed to let you know you're assuming int->bool conversion, but 1) why would you even still use bool (==typedef int mostly) and 2) why would an if(2) not convert 2 to true or false, I thought that was the whole idea of a predicate, being true or false.
What is going on here? I don't even get why the warning is triggered in the first place. I thought the first bit of code already returned a bool anyways.
Streams have an implicit conversion operator that returns a void*. (That's a version of the safe bool idiom. It's done this way because there is less contexts in which void* compiles than bool, so there's less contexts in which the implicit conversion could kick in unwanted.)[1]
Streams' operator>>() returns a reference to its left operand - the stream. That's so you can chain input operations: strm >> value1 >> value2 is executed as ((strm >> value1) >> value2).
Now, when you say if( strm >> value ), strm >> value is executed and a stream returned. In order to put that into an if statement, the implicit conversion into void* is performed, and that pointer is then checked for being NULL or not.
That's no different from if(ptr), the if statement implicit converts its condition to bool, but compilers would never warn about that, because the condition not being a bool is so common.
With the return, this is different. If you want to return a certain type, usually the expression you return should be of that type. VC's warning is quite annoying and for me in 99 out of 100 times it was superfluous. But the remaining 1% (never a performance concern, BTW; I think that is silly about the warning) made me glad the warning is there.
The workaround for this warning is to
return 0 != <expression>
where <expression> is whatever you think should be considered a boolean value.
[1] ISTR Stroustrup writing somewhere that an operator bool() would silently compile if you messed up the operators: ostrm >> 5; (note the >> instead of <<) would compile fine, but silently do the wrong thing. (It converts the boolean to an integer and right-shifts that 5 times, then discard the value.)
The difference between the cases is probably that return needs to generate a return value, while if doesn't have to generate any value, but simply branch. The warning is apparently that a new data object would have to be created, so it's triggered by return but not by if.
If conditions are evaluated as zero or non-zero, not converted to Booleans.
i.e. if( 1 ) doesn't generate a warning, because 1 is non-zero.
if( true ) doesn't generate a warning, because true is evaluated as non-zero.
So, integers, pointers, booleans are all converted to 'zero or non-zero', not to booleans.
But when you attempt to return an integer value from a function with a boolean return, it has to assume you want to mimic that behaviour. That's why it indicates "I'm assuming you want to cast 'non-zero to true and zero to false', and you get the warning.
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 ==.