In the code base I have many sections that are either turned on or off depending on enabled features. The aim is to generate program code as small as possible (Arduino with 32kB program memory).
Lets say I have the code as below:
class A
{
private:
#ifdef FEATURE
int m_optA;
int m_optB;
#endif
public:
#ifdef FEATURE
void SetFeatureOptions(int optionA, int optionB)
{
m_optA = optionA;
m_optB = optionB;
}
#endif
};
#ifdef FEATURE
#define SETFEATUREOPTIONS(a, b) SetFeatureOptions(a, b)
#else
#define SETFEATUREOPTIONS(a, b) Noop() // ????? <-- what should I put here to perform NOOP
#endif
class B
{
public:
A m_a;
void DoStuff()
{
// approach 1:
#ifdef FEATURE
m_a.SetFeatureOptions(1, 34);
#endif
// approach 2:
// Lets have a macro - see above
// This way each time I want to call SetFeatureOptions but only when FEATURE is defined
// I need no ifdef/endif scope to be used explicitely.
m_a.SETFEATUREOPTIONS(1, 34);
}
}
Is there a way to resolve SETFEATUREOPTIONS macro so it compiles and yet doesn't generate any code, when called as a method name?
Why way is to implement Noop() method in class A, but I was wondering if there is better way, that is not requiring adding a null method like mentioned above Noop(). I am not sure if adding inline Noop(){} will add some bytes to the program memory or not (Release, optimized code).
IMPORTANT: This has to compile with C++98 compiler.
Just write:
void SetFeatureOptions(int optionA, int optionB)
{
#ifdef FEATURE
m_optA = optionA;
m_optB = optionB;
#endif
}
and make sure you compile with optimizations turned on. Your compiler is smart enough to delete the function call, if the function is defined in the header file and is empty.
If the function is defined in a different .cpp file the compiler won't know it's empty, so it won't delete the call.
I have come to fact that all major compilers will not do tail call optimization if a called function does not return (i.e. marked as _Noreturn/[[noreturn]] or there is a __builtin_unreachable() after the call). Is this an intended behavior and not a missed optimization, and if so why?
Example 1:
#ifndef __cplusplus
#define NORETURN _Noreturn
#else
#define NORETURN [[noreturn]]
#endif
void canret(void);
NORETURN void noret(void);
void foo(void) { canret(); }
void bar(void) { noret(); }
C: https://godbolt.org/z/pJfEe-
C++: https://godbolt.org/z/-4c78K
Example 2:
#ifdef _MSC_VER
#define UNREACHABLE __assume(0)
#else
#define UNREACHABLE __builtin_unreachable()
#endif
void f(void);
void foo(void) { f(); }
void bar(void) { f(); UNREACHABLE; }
https://godbolt.org/z/PFhWKR
It's intentional, though perhaps controversial since it can seriously harm stack usage properties; for this reason I've even resorted to tricking the compiler to think a function that can't return can. The reasoning is that many noreturn functions are abort-like (or even call abort), and that it's likely someone running a debugger wants to be able to see where the call happened from -- information which would be lost by a tail call.
Citations:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=10837
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56165
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67327
etc.
I usually use the #define macro to add code that will be here while compiling as debug time and not while compiling as release. For instance:
#ifdef NDEBUG
# define LOG(msg) (void)msg
#else
# define LOG(msg) MyDebugLogger(msg)
#endif
Instead of that, I was thinking of using plain function and, just not providing the body for the release method:
void MyDebugLogger(std::string const& msg);
In MyDebugLogger.cpp:
void MyDebugLogger(std::string const& msg)
{
#ifdef NDEBUG
std::clog << msg << "\n"; // Or whatever
#else
(void)msg;
#endif
}
I'm expecting that the compilers will have the power to strip out the call and add no extra cost in Release. Am I correct?
For some reason, could it be a bad practice?
EDIT: My question is: If I use macros as before, I know that in Release mode, the executable will be smaller and faster, as all the code has been removed.
If I use the function, will it be the same? As the compiler may understand that the function does nothing and is not necessary. (Or it will add an extra, even small, for calling an empty function)
practically you would do the same as with the macro:
void MyDebugLogger(std::string const& msg)
{
#ifdef NDEBUG
std::clog << msg << "\n"; // Or whatever
#endif
}
You'r example should work, with a little tweak. In your current version the compiler "sees" just the function signature and will emit a call to it's symbol, which will later be resolved via the linker, so it can't optimize it out on it's own. (Link Time Optimizations might help with that, but that depends very much on you'r setup and dynamic linking would make this impossible). So maybe try something like this
in the header:
// Assuming you are using clang or gcc,
// but is required to not give an error by the standard and probably
// not even needed.
[[gnu::always_inline]]
void MyDebugLogger(std::string const& msg [[maybe_unused]])
{
#ifdef NDEBUG
MyDebugLoggerImplementation(msg);
#endif
}
And then implement it in you .cpp file. Another benefit of this method is that you
method needs the Logger to be compiled with NDEBUG while this method gives the client code the choice.
I've a very basic class, name it Basic, used in nearly all other files in a bigger project. In some cases, there needs to be debug output, but in release mode, this should not be enabled and be a NOOP.
Currently there is a define in the header, which switches a makro on or off, depending on the setting. So this is definetely a NOOP, when switched off. I'm wondering, if I have the following code, if a compiler (MSVS / gcc) is able to optimize out the function call, so that it is again a NOOP. (By doing that, the switch could be in the .cpp and switching will be much faster, compile/link time wise).
--Header--
void printDebug(const Basic* p);
class Basic {
Basic() {
simpleSetupCode;
// this should be a NOOP in release,
// but constructor could be inlined
printDebug(this);
}
};
--Source--
// PRINT_DEBUG defined somewhere else or here
#if PRINT_DEBUG
void printDebug(const Basic* p) {
// Lengthy debug print
}
#else
void printDebug(const Basic* p) {}
#endif
As with all questions like this, the answer is - if it really matters to you, try the approach and examine the emitted assembly language.
Compiler possibly may optimize this code, if it knows printDebug function implementation at compilation time. If printDebug is in another object module, this possibly may be optimized only by linker, using the whole program optimization. But the only way to test this is to read compiler-generated Assembly code.
If you already have PRINT_DEBUG macro, you can extend it by the way as TRACE is defined:
#define PRINT_DEBUG // optional
#ifdef PRINT_DEBUG
#define PRINT_DEBUG_CALL(p) printDebug(p)
#else
#define PRINT_DEBUG_CALL(p)
#endif
void printDebug(const Basic* p);
class Basic {
Basic() {
simpleSetupCode;
// this should be a NOOP in release,
// but constructor could be inlined
PRINT_DEBUG_CALL(this);
}
};
--Source--
// PRINT_DEBUG defined somewhere else or here
#if PRINT_DEBUG
void printDebug(const Basic* p) {
// Lengthy debug print
}
#endif
#if PRINT_DEBUG
#define printDebug _real_print_debug
#else
#define printDebug(...)
#endif
This way the preprocessor will strip all debug code before it even gets to the compiler.
Currently most of the optimizations are done at compile time. Some compilers as LLVM are able to optimize at link time. This is a really interesting idea. I suggest you to take a look at.
Waiting for these kind of optimization, what you can do is the following. Define a macro that let you include the following statement depending on whether DEBUG is defined or not.
#ifdef DEBUG
#define IF_DEBUG (false) {} else
#else
#define IF_DEBUG
#endif
You can the use it like this
Basic() {
simpleSetupCode;
// this should be a NOOP in release,
// but constructor could be inlined
IF_DEBUG printDebug(this);
}
which is already much more readable than
Basic() {
simpleSetupCode;
// this should be a NOOP in release,
// but constructor could be inlined
#if DEBUG
printDebug(this);
#endif
}
Note that you can use it as if it was a keyword
IF_DEBUG {
printDebug(this);
printDebug(thas);
}
errm, why not use the pre-processor macro differently?
Just of the top of my head, something like:
#define DEBUG_TRACE(p)
#ifdef PRINT_DEBUG
printDebug(p);
#else
;
#endif
Is it possible to do something like this
#ifdef SOMETHING
#define foo //
#else
#define foo MyFunction
#endif
The idea is that if SOMETHING is defined, then calls to foo(...) become comments (or something that doesn't get evaluated or compiled), otherwise it becomes a call to MyFunction.
I've seen __noop used, but I don't believe I can use that.
EDIT(s):
I don't think I can really use a macro here, because MyFunction takes a variable number of arguments.
Also, I'd like to make it so the arguments are NOT evaluated! (So doing something like commenting out the body of MyFunction doesn't really give me what I need, as the arguments will still be evaluated)
Try this:
#ifdef SOMETHING
#define foo(x)
#else
#define foo(x) MyFunction(x)
#endif
If your function has several arguments, then:
#ifdef SOMETHING
#define foo(x,y,z)
#else
#define foo(x,y,z) MyFunction(x,y,z)
#endif
If your function has a variable number of arguments, then your compiler may support so-called "variadic macros", like this:
#ifdef SOMETHING
#define foo(...)
#else
#define foo(...) MyFunction(__VA_ARGS__)
#endif
The reason which I've seen this kind of thing used in practice is to get rid of logging functions from a release build. However, see also Separate 'debug' and 'release' builds? in which people question whether you should even have different builds.
Alternatively, instead of redefining the function call as nothing, Jonathan's comment to this answer suggested doing something like the following:
#ifdef SOMETHING
#define foo(...) do { if (false) MyFunction(__VA_ARGS__) } while (0)
#else
#define foo(...) do { if (true) MyFunction(__VA_ARGS__) } while (0)
#endif
The reasoning for doing this is so that the function call is always compiled (so it won't be left with gratuitous errors like references to deleted variables), but only called when needed: see Kernighan & Pike The Practice of Programming and also the Goddard Space Flight Center programming standards.
From a debug.h file (originating from 1990, and therefore not using __VA_ARGS__):
/*
** Usage: TRACE((level, fmt, ...))
** "level" is the debugging level which must be operational for the output
** to appear. "fmt" is a printf format string. "..." is whatever extra
** arguments fmt requires (possibly nothing).
** The non-debug macro means that the code is validated but never called.
** -- See chapter 8 of 'The Practice of Programming', by Kernighan and Pike.
*/
#ifdef DEBUG
#define TRACE(x) db_print x
#else
#define TRACE(x) do { if (0) db_print x; } while (0)
#endif /* DEBUG */
With C99, there's no longer a need for the double parentheses trick. New code should not use it unless C89 compatibility is an issue.
Maybe an easier way to do this would be to conditionally omit the body of the function?
void MyFunction() {
#ifndef SOMETHING
<body of function>
#endif
}
Unless you specifically don't want a function call to be made at all, this seems like a clean way to achieve your goal.
Unfortunately the current C++ version doesn't support variadic macros.
However, you can do this:
#ifdef SOMETHING
#define foo
#else
#define foo(args) MyFunction args
#endif
// you call it with double parens:
foo((a, b, c));
If, in the case you don't want foo called, you define it as:
void foo() {}
any calls to foo() should be optimized way.
What about something along these lines:
#ifdef NDEBUG
#define DEBUG(STATEMENT) ((void)0)
#else
#define DEBUG(STATEMENT) (STATEMENT)
#endif
You would use it like this to log debugging messages:
DEBUG(puts("compile with -DNDEBUG and I'm gone"));
A non-generic version for formatted output with additional debugging information using C99 variadic macros and the __func__ identifier could look like this:
#ifdef NDEBUG
#define Dprintf(FORMAT, ...) ((void)0)
#define Dputs(MSG) ((void)0)
#else
#define Dprintf(FORMAT, ...) \
fprintf(stderr, "%s() in %s, line %i: " FORMAT "\n", \
__func__, __FILE__, __LINE__, __VA_ARGS__)
#define Dputs(MSG) Dprintf("%s", MSG)
#endif
Here's how you'd use these macros:
Dprintf("count = %i", count);
Dputs("checkpoint passed");
Likely, you don't want to do the simple "code removal" as suggested,
because your callers will be expecting the side effects of the
arguments to happen. Here are some troublesome caller snippets that
should get you thinking:
// pre/post increment inside method call:
MyFunction(i++);
// Function call (with side effects) used as method argument:
MyFunction( StoreNewUsernameIntoDatabase(username) );
If you were to disable MyFunction by simply saying:
#define MyFunction(x)
then the side effects that the callers were expecting would go away,
and their code would break, and be quite difficult to debug. I like
the "sizeof" suggestion above, and I also like the suggestion to just
disable the body of MyFunction() via #ifdef's, although that means
that all callers get the same version of MyFunction(). From your
problem statement, I presume that's not actually what you want.
If you really need to disable MyFunction() via preprocessor defines on
a per-source-file basis, then I'd do it like this:
#ifdef SOMETHING
#define MyFunction(x) NoOp_MyFunction(x)
int NoOp_MyFunction(x) { }
#endif
You could even include the implementation of NoOp_MyFunction() inside
the source & headers for MyFunction(). You also have the flexibility
to add extra logging or debugging information in NoOp_MyFunction() as
well.
No, the C and C++ Standards say you cannot #define something to be a comment, so
#define foo //
won't work.
#ifdef SOMETHING
#define foo sizeof
#else
#define foo MyFunction
#endif
I'm assuming that foo is a printf style function? Anyways, this won't work with a zero parameter function, but if that were the case, you would already know what to do. If you really want to be anal you can use (void)sizeof but that's probably unnecessary.
I'm a little reluctant to post this answer because it's use of macro hackery can become the source of problems. However - if the calls to the function you want to have disappear are always used alone in a statement (ie., they are never part of a larger expression), then something like the following could work (and it handles varargs):
#ifdef SOMETHING
#define foo (1) ? ((void) 0) : (void)
#else
#define foo MyFunction
#endif
So if you have the line of code:
foo( "this is a %s - a++ is %d\n", "test", a++);
it will end up after the preprocessing step as either:
MyFunction( "this is a %s - a++ is %d\n", "test", a++);
or
(1) ? ((void) 0) : (void)( "this is a %s - a++ is %d\n", "test", a++);
which turns the pseudo-function's parameter list into a bunch of expressions separated by the comma operator that will never be evaluated, since the conditional always returns the ((void) 0) result.
A variant of this is something close to what ChriSW and Jonathan Leffler suggested:
#ifdef SOMETHING
#define foo if (0) MyFunction
#else
#define foo if (1) MyFunction
#endif
This is slightly different in that it does not require the compiler to support variadic macros (__VA_ARGS__).
I think this can be useful for eliminating debug trace function calls which are generally never combined into a larger expression, but beyond that I think it's a dangerous technique.
Note the potential for problems - especially if the parameters in the call produce side-effects (this is a general problem with macros - not just this hack). In the example, the a++ will be evaluated only if SOMETHING is defined in the build, otherwise it's not. So if code after the call depends on the value of a to be incremented, one of the builds has a bug.
If I remember correctly, you should be able to #define your macro to "nothing" and that will cause the compiler to ignore that call
#define foo()
foo(); // this will be ignored
What about surrounding each call to myFunction with
#ifdef SOMETHING
myFunction(...);
#endif
?