Will A Compiler Remove An If Block That Always Evaluates to Zero? - c++

Will the compiler remove this if statement?
#define DEBUG 0
int main(int argc, char ** argv)
{
if(DEBUG)
{
...
}
return 0;
}
I tried to google this, and search stackoverflow but I think my search terms were bad because I couldn't find the information.
If this is optimized what would I want to read about to learn about the optimization?
Constantin

Yes, any decent C/C++ compiler will remove such if block.

I'm not sure if a compiler can optimize it away. I guess yes since in this situation you couldn't have any side effect, so it can be safely removed without changing semantics of the code.
In any case guessing is not nice and relying on an optimization is not nice too.
Why don't you use a #ifdef .. #endif block instead that a code block?
#define DEBUG
#ifdef DEBUG
...
#endif
In this way you will have a sure outcome.

You don't need to guess. Compile and step with debugger watching assembly instructions. You don't even need to be well familiar with assembly to see if there is actual code generated for lines in question or not.

You cannot make the universal statement that every compiler will optimize the same things the same way. Likewise any compiler that might happen to do it today might not in some future version.
Yes, a number of compilers today can and will do that but that doesnt mean you should plan for it or expect it. If you dont want that code there, comment it out, ifdef it out or remove it.
As mentioned by others, try it and find out for yourself. If you are debugging something and suspect that this has or has not happened, simply look and find out...

You got good answers to check it in your compiler assembly output. I would like to share similar idiom that is very usefull to me sometimes:
int main(int argc, char ** argv)
{
const bool bDebug = false;
if(bDebug)
{
...
LOG(""); /// some heavy loging here
}
return 0;
}
so I leave such if-s in some relevant places in my code, and when I get a bug report that something bad happend I step through code and when I need to ouput some large arrays/data structures, I modify from debugger bDebug variable (actually I name them bVerbose), and then allow code to enter such IF-s. You dont have to recompile code to add heavy logging.

Related

flycheck cppcheck stop checking unusedStructMember

So I've recently begun using flycheck within emacs. Overall it's working great, but I've been having a small issue with flycheck using cppcheck in c++ mode. I'm getting a bunch of unusedStructMember warnings, likely due to not using that member within the present file. I was wondering if it is possible to tell flycheck to disable the unusedStructMember warnings from cppcheck, and if so, how would I go about doing so? My emacs-lisp skills are mostly non-existent and so far I haven't found anyone with a similar problem.
Thanks!
This is not an emacs configuration but something depends on the backend you use for C++ flycheck (i.e. cppcheck).
I just took a look at the manual of cppcheck. Obviously you can do it by inline pragmas. For example:
void f() {
char arr[5];
// cppcheck-suppress arrayIndexOutOfBounds
arr[10] = 0;
}
In your case, you'll need something like:
// cppcheck-suppress unusedStructMember

Stopping debugger at an optimized out line of code

If I want to stop in an empty block of code it's always a problem.
if (...)
{ // I want the debugger to stop here!
}
If I add an arbitrary line of code which does not affect program behaviour it is likely to be optimized out, depending on the line
if (...)
{
int a;
a = a; // won't work
}
if (...)
{
int a;
int b = a; // will work
}
So the 2 questions arise here:
1) What is the simplest one-line code which will NOT be optimized out (but will really do nothing!), which I can use to stop the debugger?
2) Is there a way to switch all of optimizations so that to be able to stop at an arbitrary line of code? Compiler flag -O0 doesn't work.
A good enough one-line code could be some useful and interesting assert statement with a condition which would not be constant-folded by the compiler. Often some meaningful and useful assert (p!=NULL) orassert(i>0) where p is some existing pointer variable or formal, or i is some existing signed integer variable or formal, is enough.
BTW, you are in the debugging phase of your project, so adding good enough meaningful assert statements is helpful. Of course you want the <cassert> header to be included.
Don't forget that assert(3) statements are skipped if you compile with the -DNDEBUG flag.
You could also use (on Linux/x86) asm volatile ("nop"). Notice that the debugger needs some code to put a breakpoint at. You don't want an empty code.
What about using a static breakpoint?
#include <sys/sdt.h>
if (condition)
DTRACE_PROBE(myapp, foo);
Now you can set a breakpoint in GDB:
break -probe-stap myapp:foo
You can even use:
DTRACE_PROBE1(myapp, foo, condition);
with:
break -probe-stap myapp:foo if $_probe_arg0

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.

Danger in using nested comments for quickly (de)activating code blocks in C++

I'm currently using nested comments to quickly activate/deactivate code during testing, the way I'm doing it is like this :
//* First Case, Activated
DoSomething();
/**/
/* Second Case, De-Activated
DoSomethingElse();
/**/
I can activate, deactivate the code blocks by simply adding or deleting a '/'.
The compiler warns me about this, as nested comments are bad, but in reality, is it dangerous to use these comments?
This is how people normally do this:
#if 0
//...
#endif
or
#define TESTWITH
#ifdef TESTWITH
//..
#endif
Yes, you will often end up overcommenting or undercommenting and having code other than you expect active and this will make debugging very confusing. Using // is much more reliable for that - you'll have to type more, but it's more predictable.
Not a direct answer, but have you considered #ifdef instead?
#define DOSOMETHING
#ifdef DOSOMETHING
DoSomething();
#else
DoSomethingElse();
#endif
Why do you feel the need to toggle code blocks on and off so often anyway? Most likely, you're doing something wrong at a higher level.
Perhaps you should be using source control, and simply create two (or more) branches, to test out different versions of your code.
Or perhaps you should refactor your code so that, instead of commenting out a whole block of code, you only need to change a single function call.
There is nothing wrong with abusing nested comments like this, but it makes your code harder to read, and it solves a problem which typically should be solved at a whole different level.
Here's how you can get into trouble:
//* First Case, Activated
DoSomething();
/**/
/* Second Case, De-Activated
/* Comment about DoSomethingElse */
DoSomethingElse();
/**/
Now, your second case will execute, because the closing of the regular comment will close your note off, and the compiler won't detect anything is amiss.
Of course, this can be averted by never using the /**/ style comments, and it depends on your environment if that's a reasonable thing to do. And a syntax-highlighting editor (even including the Stack Overflow answer editor) will tip you off to what's going on. But why introduce the possibility?
This also falls into the category of "cute." You're mixing the two different commenting syntaxes. So long as everyone understands what's going on and plays by the rules, you'll be fine. But as soon as somebody doesn't you're in trouble.

How to properly rewrite ASSERT code to pass /analyze in msvc?

Visual Studio added code analysis (/analyze) for C/C++ in order to help identify bad code. This is quite a nice feature but when you deal with and old project you may be overwhelmed by the number of warnings.
Most of the problems are generating because the old code is doing some ASSERT at the beginning of the method or function.
I think this is the ASSERT definition used in the code (from afx.h)
#define ASSERT(f) DEBUG_ONLY((void) ((f) || !::AfxAssertFailedLine(THIS_FILE, __LINE__) || (AfxDebugBreak(), 0)))
Example code:
ASSERT(pBytes != NULL);
*pBytes = 0; // <- warning C6011: Dereferencing NULL pointer 'pBytes'
I'm looking for an easy, clean and safe solution to solve these warnings that does not imply disabling these warnings. Did I mention that there are lots of occurrences in current codebase?
/analyze is not guaranteed to yield relevant and correct warnings.
It can and will miss a lot of issues, and it also gives a number of false positives (things it identifies as warnings, but which are perfectly safe and will never actually occur)
It is unrealistic to expect to have zero warnings with /analyze.
It has pointed out a situation where you dereference a pointer which it can not verify is always valid. As far as PREfast can tell, there's no guarantee that it will never be NULL.
But that doesn't mean it can be NULL. Just that the analysis required to prove that it's safe is too complex for PREfast.
You may be able to use the Microsoft-specific extension __assume to tell the compiler that it shouldn't produce this warning, but a better solution is to leave the warning. Every time you compile with /analyze (which need not be every time you compile), you should verify that the warnings it does come up with are still false positives.
If you use your asserts correctly (to catch logic error during programming, guarding against situations that cannot happen, then I see no problem with your code, or with leaving the warning. Adding code to handle a problem that can never occur is just pointless. You're adding more code and more complexity for no reason (if it can never occur, then you have no way of recovering from it, because you have absolutely no clue what state the program will be in. All you know is that it has entered a code path you thought impossible.
However, if you use your assert as actual error handling (the value can be NULL in exceptional cases, you just expect that it won't happen), then it is a defect in your code. Then proper error handling (exceptions, typically) is needed.
Never ever use asserts for problems that are possible. Use them to verify that the impossible isn't happening. And when /analyze gives you warnings, look at them. If it is a false positive, ignore it (don't suppress it, because while it's a false positive today, the code you check in tomorrow may turn it into a real issue).
PREFast is telling you that you have a defect in your code; don't ignore it. You do in fact have one, but you have only skittered around acknowleging it. The problem is this: just because pBytes has never been NULL in development & testing doesn't mean it won't be in production. You don't handle that eventuality. PREfast knows this, and is trying to warn you that production environments are hostile, and will leave your code a smoking, mutilated mass of worthless bytes.
/rant
There are two ways to fix this: the Right Way, and a hack.
The right way is to handle NULL pointers at runtime:
void DoIt(char* pBytes)
{
assert(pBytes != NULL);
if( !pBytes )
return;
*pBytes = 0;
}
This will silence PREfast.
The hack is to use an annotation. For example:
void DoIt(char* pBytes)
{
assert(pBytes != NULL);
__analysis_assume( pBytes );
*pBytes = 0;
}
EDIT: Here's a link describing PREfast annotations. A starting point, anyway.
Firstly your assertion statement must guarantee to throw or terminate the application. After some experimentation I found in this case /analyse ignores all implementation in either template functions, inline functions or normal functions. You must instead use macros and the do{}while(0) trick, with inline suppression of
If you look at the definition of ATLENSURE() Microsoft use __analyse_assume() in their macro, they also have several paragraphs of very good documentation on why and how they are migrating ATL to use this macro.
As an example of this I have modified the CPPUNIT_ASSERT macros in the same way to clean up thousands of warnings in our unit tests.
#define CPPUNIT_ASSERT(condition) \
do { ( CPPUNIT_NS::Asserter::failIf( !(condition), \
CPPUNIT_NS::Message( "assertion failed" ), \
CPPUNIT_SOURCELINE() ) ); __analysis_assume(!!(condition)); \
__pragma( warning( push)) \
__pragma( warning( disable: 4127 )) \
} while(0) \
__pragma( warning( pop))
remember, ASSERT() goes away in a retail build so the C6011 warning is absolutely correct in your code above: you must check that pBytes is non-null as well as doing the ASSERT(). the ASSERT() simply throws your app into a debugger if that condition is met in a debug bug.
I work a great deal on /analyze and PREfast, so if you have other questions, please feel to let me know.
You seem to assume that ASSERT(ptr) somehow means that ptr is not NULL afterwards. That's not true, and the code analyzer doesn't make that assumption.
My co-author David LeBlanc would tell me this code is broken anyway, assuming you're using C++, you should use a reference rather than a pointer, and a ref can't be NULL :)