Q_ASSERT release build semantics - c++

I can't find a clear statement on the semantics of Q_ASSERT under release builds. If there is no assertion checking, then is the asserted expression evaluated at all?
Consider the following code
Q_ASSERT(do_something_report_false_if_failed());
Will do_something_report_false_if_failed() run under all potential Qt build configurations? Would it be safer (even though a bit more verbose and less readable) to do this instead:
bool is_ok = do_something_report_false_if_failed();
Q_ASSERT(is_ok)
The latter approach has the downside that ASSERT failures are less verbose, but perhaps it shows more clearly that the statement is executed?

The expression inside the Q_ASSERT will not be evaluated in non-debug build configurations.
Consider the source code below from the Qt repo.
#if !defined(Q_ASSERT)
# ifndef QT_NO_DEBUG
# define Q_ASSERT(cond) ((!(cond)) ? qt_assert(#cond,__FILE__,__LINE__) : qt_noop())
# else
# define Q_ASSERT(cond) qt_noop()
# endif
#endif
If QT_NO_DEBUG is defined, then the entire Q_ASSERT statement is replaced with a qt_noop(), thereby removing any expression that it previously contained.
Never rely on any side effects created by an expression inside a Q_ASSERT statement. Technically it is still possible to ensure that QT_NO_DEBUG is not defined in a specific build configuration, but this is not a Good Idea™.

This seems to be different in Qt5.5 (but not earlier - see Qt5.4):
#if !defined(Q_ASSERT)
# if defined(QT_NO_DEBUG) && !defined(QT_FORCE_ASSERTS)
# define Q_ASSERT(cond) do { } while ((false) && (cond))
# else
# define Q_ASSERT(cond) ((!(cond)) ? qt_assert(#cond,__FILE__,__LINE__) : qt_noop())
# endif
#endif
I'm now getting lots of "​warning C4127: conditional expression is constant" in Visual Studio 2013.
Update:
Qt5.5 release notes say:
Q_ASSERT will now expand the condition even in release mode when
asserts are disabled, albeit in an unreachable code path. This
solves compiler warnings about variables and functions that were
unused in release mode because they were only used in assertions.
Unfortunately, codebases that hid those functions and variables
via #ifndef will need to remove the conditionals to compile with Qt 5.5.

Related

Exclude parts from compilation - still syntax-check

We have a pretty large project here in C++/.NET/Visual Studio, for performance testing we incuded some code that makes it possible to evaluate the execution time between certain points.
PERFORMANCE_TEST BeginMeasureTime("execute someCode")
someCode
PERFORMANCE_TEST EndMeasureTime("execute someCode")
Usually while developing the PERFORMANCE_TEST macro would be set to // so the evaluation code is switched off. So if code / interfaces etc. change and the code after the PERFORMANCE_TEST macro becomes invalid, the developer will not notice that.
Is there any smarter way to have the performance evaluation code only built in a special version of the project but still make sure that it stays consistent? How would you normally do something like that?
One easy way would be to change
PERFORMANCE_TEST xxx
to
PERFORMANCE_TEST(xxx)
Then instead of
#if PERFORMANCE_TEST_ENABLED
#define PERFORMANCE_TEST
#else
#define PERFORMANCE_TEST //
#endif
you could have
#if PERFORMANCE_TEST_ENABLED
#define PERFORMANCE_TEST(x) {x;}
#else
#define PERFORMANCE_TEST(x) if(0) { x; }
#endif
An optimizing compiler should generate no code for the second version if performance tests are disabled (or at the very least it'll not branch on the if), but it'll still be part of the compilation.
Alternatively, if build times aren't a huge concern you could simply always build both versions into separate directories.
It's been a while since I did something like this the following should be what you want. If the MACRO is defined then the function is included, else it the function is a noop and compiled out the code.
#ifdef MACRO
#define MACRO_NAME(arg1, arg2, ...) [code to expand to]
#else
#define MACRO_NAME(arg1, arg2, ...) noop
#endif
Update:
Ok so I slightly got the question a bit incorrect.
Most static analysis tools can be configured to scan certain #defines
CPPCheck for example can be given the following arguments.
-D<ID> Define preprocessor symbol. Unless --max-configs or
--force is used, Cppcheck will only check the given
configuration when -D is used.
Example: '-DDEBUG=1 -D__cplusplus'.
So you can then scan the code twice, thus achieving your goal.
I would say this is the best of both before you can add more scans if you add more #define
Or you can use some of the following to scan more configurations.
-f, --force Force checking of all configurations in files. If used
together with '--max-configs=', the last option is the
one that is effective.
and
--max-configs=<limit>
Maximum number of configurations to check in a file
before skipping it. Default is '12'. If used together
with '--force', the last option is the one that is
effective.
We used this type of operation at a previous company, we build code for WIN32, Pocket PC and WM5 and WM6 all from the same code base but had static checking on all build configurations. But the end result was the removal of non redundant code in all builds.

Code littered with asserts

Hi I am programming on some device.
There is some sample with such code:
Verify(SomeFunc(argc, argv) == SDK_OK);
Verify(SomeOtherFunction(&st_initialData) == SDK_OK);
Verify(SomeOtherFunction2(x,y) == SDK_OK);
In doc, Verify is defined as 'similar' to assert.
My question is: if I build my project in Release mode, what will happen with above statements? Will they lose their power? Will the Verify have any effect still?
To avoid possible problem with above, will I have to replace above codes with checking return values like this?:
if(SomeFunc(argc, argv) == SDK_OK)
{
// we are fine
}
else
{
// handle error somehow, such that it is also available in Release mode
}
It is impossible to say, as it seems that it is your project which implements Verify, as a macro or as a function. Why don't you take a look at the implementation?
That being said, MFC framework has VERIFY macro which is similar to ASSERT, with the distinction that the expression is always evaluated, even in release build, but doesn't do anything if result of the expression is false. This might be the similar approach, as your examples seem to call some functions which can affect the system state.
I assume you mean the MFC VERIFY macro or something very similar.
Using this macro is safe for release builds. The argument is executed in any case, just the macro itself does nothing in release.
In contrast to this, the ASSERT macro is completely skipped in release builds, so the "side effects" of the argument do not happen. Therefore, VERIFY is used if the argument is required for the actual program flow, and ASSERT is used when the argument is for asserting only.
Almost certainly you will not have to replace them. If your project wanted just to remove the calls in production compilation, it would probably have just plain assert directly. Try to read the source of the project (always a good idea) and understand what he macro does.

assert() function not showing up in disassembly

My coworker just asked me to help on a problem, he has a few lines in his code as
for (long counter = 0; counter < End; )
{
...
assert(counter++ < MAX);
...
}
The problem is, when we use Visual Studio to debug line by line, seems the assert() line got skipped all the time, and counter never got incremented and thus the loop never finished.
When we look at the disassembly using VS, there is no assembly line for this assert() function. I never used assert() before, so I'm wondering is this normal and he shouldn't put any code behavior into assert() or something is wrong here with debugger or other?
Thanks.
Make sure that NDEBUG is not defined, as assert is enabled only in debug build, i.e when NDEBUG is not defined.
From here:
#ifdef NDEBUG
#define assert(condition) ((void)0)
#else
#define assert(condition) /*implementation defined*/
#endif
That is, when NDEBUG is defined, assert is no-op which is what you observe in assembly.
You should only use assert for debugging purposes.
The line
assert(counter++ < MAX);
contains logic, and it shouldn't.
In a non-debug build, it will never be executed.
assert is a macro, which is removed in release builds. So unless you're looking at a debug build, don't expect to see any assert code.
And because assert is a macro, and not a function, it's not likely to look like a single function call either.
If the code is built under Release Mode, the assert statements will not be included. Is your coworker using Release Mode?
Visual Studio's optimization settings may also remove the assert statements.
Couldn't your coworker change the for loop to not use the assert statement?
Asserts typically get removed from release builds and therefore are executed only for debug builds. You should never have any side effects affecting program logic in assert.

Defining giving a warning in C++

I want to declare a debug flag is on or off in these both ways:
#define inDebugMode true
or
const bool inDebugMode = true;
The compiler in Visual Studio 2010 always gives a warning:
warning C4127: conditional expression is constant
Why is that? How can I declare it correctly?
Without seeing the code, I suspect you have the following construct:
if (inDebugMode)
{
}
which will always be true, hence the warning.
Recommend using the preprocessor instead of if:
#define inDebugMode 1
#if inDebugMode
#endif
This will remove the warning and prevent the debugging code being compiled when unrequired. Note you can also specify the value of a macro via the compiler switch /D:
cl.exe /DinDebugMode=1 ...
but you need to ensure you rebuild all sources if you choose the command line option, not just the changed sources.
This warning is not for the definition but for the use of it.
lets say you write in your code something like:
if (inDebugMode)
{
//your code
}
when the compiler encounter it (after the precompile in case of the define) this is always true and there it thinks the "if" is not needed. that's way it's only a warning not a error.
in order to avoid it you can do like that:
#define inDebugMode 1
//some code
#if inDebugMode
//your code you only want to run in debug
#endif
this way if you not in debug all the code in the "#if" section will be omitted by the precompiler and the compiler wouldn't have a problem.
If you don't like preprocessor directives and would like to use the const bool, then you may disable "warning C4127" directly (Project Properties / C/C++ / Advanced / Disable Specific Warnings / type "4127").

Empty "release" ASSERT macro crashes program?

Take a look at this code:
#include <cassert>
#ifdef DEBUG
#define ASSERT(expr) assert(expr)
#else
#define ASSERT(expr)
#endif /* DEBUG */
The program will run only if I have DEBUG defined, otherwise it will hang and terminate with no results. I am using MinGW in Eclipse Indigo CDT. Advice is appreciated!
It's hard to tell without looking at the actual code that is causing the issue. My guess: you are evaluating an expression with side-effects within an ASSERT(). For instance, ASSERT( ++i < someotherthing ) whithin a loop. You could confirm by temporary modifying the macro definition to just expr on NDEBUG builds. After confirming this is the cause, go to each and every ASSERT call you are issuing to ensure that the expressions are side-effects free.
You are almost certainly abusing assertions. An assertion expression must never have side effects.
When you say, assert(initialize_critical_space_technology());, and then you omit this entire line in the release build, you can imagine for yourself what will happen.
The only safe and sane way to use assertions is on values:
const bool space_init = initialize_critical_space_technology();
assert(space_init);
Some people introduce a VERIFY macro for something that always executes the code:
#define VERIFY(x) (x) // release
#define VERIFY(x) (assert(x)) // debug