12

Consider a function

void f() {
   assert(condition);

   ...
}

In debug mode, where asserts are enabled, the compiler is free to assume condition holds, since the remaining code will not be executed if it does not.

However, in release mode, I believe the compiler will only see

void f() {
   ...
}

and can no longer assume condition.

Are there any compiler directives or static assert tricks to let compiler know about certain invariants?

arhzu
  • 550
  • 3
  • 13
  • *compiler is free to assume condition holds* can u explain what you meant by it? – Rakib May 17 '14 at 08:37
  • compiler does not assume anything, it actually *checks* if the condition holds, raises error if not. – Rakib May 17 '14 at 08:40
  • 2
    @RakibulHasan if the compiler performs reachability analysis, it can infer that the code following the assert will be executed only if the condition holds. In other words, during "..." it can assume the condition is true (in debug mode only). – arhzu May 17 '14 at 09:12
  • That reachability analysis is an optimization. Which means it would *not* be performed in a debug build, when assertions are enabled. So this question is somewhat nonsensical. – Cody Gray - on strike May 17 '14 at 09:32
  • 1
    @CodyGray toy example: `bool test(int a) { assert(a>0); return a > 0; }`. In debug mode, the compiler could infer (if optimizations would be turned on) that the function always returns true. In release mode, it cannot since the assert is no longer there. Thus, it is a missed optimization opportunity. – arhzu May 17 '14 at 10:55
  • No, it is not a missed opportunity, as the assertion _may not hold_ at all times, even if it is desired to and has been verified while debugging the application. – Jinxed Feb 05 '18 at 10:29
  • 1
    @Cody Gray, in debug builds, you can still have optimization, in which case the optimizer could return true, since the assert is the moral equivalent (in debug mode) of an early return, right? I realize assert happens at run time and so once it’s disabled in release, the optimizer can’t see it, but I could see wanting to have a macro that asserts in debug builds but is a static optimizer hint in release once you are certain the assert always holds. – Ben May 23 '18 at 11:57

2 Answers2

7

This can't be done in portable C or C++.

Some compilers provide intrinsic functions such as __assume (for MSVC) and __builtin_unreachable (for GCC, ICC, and Clang), that can be used for this purpose.

For example:

void f() {
    __assume(condition); //For MSVC
    /*...*/
}

void f() {
    if (!condition) __builtin_unreachable(); //for GCC and Clang
    /*...*/
}
Mankarse
  • 39,818
  • 11
  • 97
  • 141
  • This has been discussed in further detail [here](http://blog.regehr.org/archives/1096). Generally speaking, `__builtin_unreachable()` could be replaced by any expression with undefined behaviour, and if the compiler could detect that, the effect would be the same (in principle). – Mankarse Sep 11 '16 at 03:50
0

A part the verb "assume", that makes the question a little obscure, (and makes me worry abot you have a real understandment of what a compiler really does) the assert is a macro that is replaced by nothing when NDEBUG is defined (normally in release builds), and -when used in debug builds- throws an error if condition is not true.

The point, here, is that the program is "correct" only if condition is always true. After you proved it (in testing builds) there is no point in continue to prove it even in release code.

The more subtle problem can be if "condition" itself has a side effect you don't want to remove in release builds.

In this case, just put "condition" out from the assert, store the result in a bool and assert on the bool, like

bool condition_fine = (condition);
assert(condition_fine);

This let condition to be evaluated in any case, but removes the error check from release builds.

Emilio Garavaglia
  • 20,229
  • 2
  • 46
  • 63