Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ compiler optimization of passed arguments

I'm using a logging module that can have reporting enabled/disabled at runtime. Calls generally go something like:

WARN(
     "Danger Will Robinson! There are "
     + boost::lexical_cast<string>(minutes)
     + " minutes of oxygen left!"
);

I'm using an inline function for WARN, but I'm curious as to how much optimization is going on behind the scenes -- evaluation of the arguments throughout the entire program would be costly. The WARN function goes something like this:

bool WARNINGS_ENABLED = false;
inline void WARN(const string &message) {
    if (!WARNINGS_ENABLED) {
       return;
    }
    // ...
}

Given that constructing the string argument has no side-effects, will the compiler optimize it out? Is a certain level of optimization required (-Ox in g++ for some x)?

like image 747
cdleary Avatar asked Nov 12 '08 00:11

cdleary


Video Answer


2 Answers

If you need to be able to selectively enable and disable the warnings at run-time, the compiler will not be able to optimize out the call.

What you need is to rename your function to WARN2 and add a macro something like:

#define WARN(s) do {if (WARNINGS_ENABLED) WARN2(s);} while (false)

This will prevent the evaluation of s at run-time unless you have warnings enabled.

The do-while stuff is a trick that allows it to be used anywhere in the code (naked statement, statement within a braced if-block, statement within an unbraced if-block, braced and unbraced while statements and so on).

like image 59
paxdiablo Avatar answered Sep 29 '22 01:09

paxdiablo


You can check what GCC/G++ do by using the -S option. This will output the code before it actually gets assembled – see gcc(1).

GCC and G++ more or less behave the same in this case. So I first translated the code into C to make some further tests:

char WARNINGS_ENABLED = 0;

inline void WARN(const char* message) {
    if (!WARNINGS_ENABLED) {
        return;
    }
    puts(message);
}

int main() {
    WARN("foo");
    return 0;
}

run gcc -O3 -S file.c and look into the output file 'file.s'
You will see that GCC didn't remove anything!

That's not what you asked for, but in order to give the compiler the opportunity to optimize that code out, you would have to make WARNINGS_ENABLED constant. An alternative is to make it static and not changing the value within that file. But: making it static has the side-effect that the symbol gets not exported.

static const char WARNINGS_ENABLED = 0;

inline void WARN(const char* message) {
  if (!WARNINGS_ENABLED) {
      return;
  }
  puts(message);
}

int main() {
    WARN("foo");
    return 0;
}

GCC then completely cleans up the code.

like image 27
Benedikt Waldvogel Avatar answered Sep 29 '22 02:09

Benedikt Waldvogel