Conditional compilation of class - c++

Normally, for classes I don't intend to include in production code I have conditional operators such as the usual:
#ifdef DEBUG_VERSION
This could also be around certain chunks of code that performs additional steps in development mode.
I've just thought (after many years or using the above): What happens if a typo is introduced in the above? It could have great consequences. Pieces of code included (or not included) when the opposite was intended.
So I'm now wondering about alternatives, and thought about creating 2 macro's:
INCLUDE_IN_DEBUG_BUILD
END_INCLUDE_IN_DEBUG_BUILD
If a typo is ever created in these, an error message is created at compile time, forcing the user to correct it. The first would evaluate to "if (1){" in the debug build and "if (0){" in the production build, so any compiler worth using should optimise those lines out, and even if they don't, at least the code inside will never be called.
Now I'm wondering: Is there something I'm missing here? Why does no-one else use something like this?

Update: I replaced the header-based approach with a build-system based approach.
You want to be able to disable not just part of the code inside a function, but maybe also in other areas like inside a class or namespace:
struct my_struct {
#ifdef DEBUG_VERSION
std::string trace_prefix;
#endif
};
So the real question seems to be: How to prevent typos in your #ifdefs? Here's something which does not limit you and which should work well.
Modify your build system to either define DEBUG_VERSION or RELEASE_VERSION. It should be easy to ensure this. Define those to nothing, e.g. -DDEBUG_VERSION or -DRELEASE_VERSION for GCC/Clang.
With this, you can protect your code like this:
#ifdef DEBUG_VERSION
DEBUG_VERSION
// ...
#endif
or
#ifndef DEBUG_VERSION
DEBUG_VERSION
// ...
#else
RELEASE_VERSION
// ...
#endif
And voila, in the second example above, I already added a small typo: #ifndef instead of #ifdef - but the compiler would complain now as DEBUG_VERSION and RELEASE_VERSION are not defined (as in "defined away" by the header) in the corresponding branches.
To make it as safe as possible, you should always have both branches with the two defines, so the first example I gave should be improved to:
#ifdef DEBUG_VERSION
DEBUG_VERSION
// ...
#else
RELEASE_VERSION
#endif
even if the release branch contains no other code/statements. That way you can catch most errors and I think it is quite descriptive. Since the DEBUG_VERSION is replaced with nothing only in the debug branch, all typos will lead to a compile-time error. The same for RELEASE_VERSION.

Related

Foolproof way to do configuration #define/#ifdef

I'm working with a moderately sized embedded C++ project that has a number of configurations for different target products. There are a good number of macros that get set for various configuration items in the different configurations and I'm trying to make that system as error-proof as possible.
Initially, I was just doing the standard thing:
#define CFG_FOO
#ifdef CFG_FOO
<code here>
#endif
but I'm always afraid I'm going to mistype a macro name in an ifdef and have a hard to find bug, because this evaluates to false without error:
#ifdef CFG_FOOO
So, I changed all the macros to this format, which requires that the macro in question be defined, defining all the ones that I want to evaluate as false to 0:
#define CFG_FOO() (1)
#define CFG_BAR() (0)
#if CFG_FOO()
<code is active>
#endif
#if CFG_BAR()
<code is inactive>
#endif
// Produces error, as desired:
#ifdef CFG_FOOO()
#endif
This was good, except that then if I accidentally enter the following (which I found I do all the time, just out of habit) it is true and the contained code is compiled:
#ifdef CFG_BAR
<this is active>
#endif
So I'm looking for a solution that:
Always generates an error for mistyped CFG_xxx item.
Doesn't allow for unintended consequences if using the wrong directive #if vs. #ifdef (it's fine if there's a error for "incorrect" usage.)
Doesn't require additional libraries/frameworks (like Boost).
Doesn't require an additional tool to process all the code (this is what I'm doing now, scanning for any #ifdef and generating an error, but that's not ideal.)
Actually removes the unneeded code. A runtime solution is probably impractical as the code size needs to be tightly controlled.
NOTE: I'm aware of the -Wundef option for gcc, but I don't believe that really helps, as the accidental #ifdef situation is still present.
My best recommendation is never get yourself into a situation where CFG_FOO is valid, CFG_BAR is valid, but both together is not valid.
We can do better by simply avoiding this problem. Specialized form for a switch ladder. CFG is a bad prefix but I'm assuming it's an artifact of minimalization and you simply will have a better one.
modeswitch.h:
#define CFGMODE_FOO 1
#define CFGMODE_BAR 2
header.h:
#if CFG == CFGMODE_FOO
#elif CFG == CFGMODE_BAR
#else
#error CFG has unsupported value
#endif
program.c
#include "modeswitch.h"
#define CFG CFGMODE_FOO
#include "header.h"
If I read this wrong and you're not using this stuff in .h files than I wonder why you have both C and C++ tags but just inline the stuff and it will still work.
My understanding is there's enough power in ## that there's a way to get rid of the pre-header but it's so hard that it doesn't meet any reasonable definition of foolproof.
Instead of repeatedly do
#if CFG_FOO()
<code is active>
#endif
since C99 or C++11, you might have once (per config)
#if CFG_FOO() // or #ifdef CFG_FOO
# define WITH_FOO(...) __VA_ARGS__
#else
# define WITH_FOO(...) /*Empty*/
#endif
And then
WITH_FOO(
<code is active>
)
Note:
It might probably break auto-indentation.
Not sure it is better than traditional way more prone to typo.
Since you're using the gcc compiler, it has a built-in #pragma for this, that throws a compiler error anytime a variable/phrase is used. This would mostly be used when you want to prevent future programmers from using things like PRINTF statements, but you can also use it in a clunkier way to eliminate the possibility that you mistype your variable names in a common way. ie. you would type something like:
#pragma GCC poison CFG_FOOO CFG_FOOD CFG_FOO0 CFG_FO
Note - I've only ever worked with this in theory, so I'm not certain it will work for you. Slightly more info in this doc:
https://gcc.gnu.org/onlinedocs/cpp/Pragmas.html

How to enable/disable spdlog logging in code?

I am creating c++ library modules in my application. To do logging, I use spdlog. But in a production environment, I don't want my lib modules to do any logging. One way to achieve turning on/off would be to litter my code with #ifdef conditionals like...
#ifdef logging
// call the logger here.
#endif
I am looking for a way to avoid writing these conditionals. May be a wrapper function that does the #ifdef checking and write it. But the problem with this approach is that I have to write wrappers for every logging method (such as info, trace, warn, error, ...)
Is there a better way?
You can disable logging with set_level():
auto my_logger = spdlog::basic_logger_mt("basic_logger", "logs/basic.txt");
#if defined(PRODUCTION)
my_logger->set_level(spdlog::level::off);
#else
my_logger->set_level(spdlog::level::trace);
#endif
spdlog::register_logger(my_logger);
You can disable all logging before you compile the code by adding the following macro (before including spdlog.h):
#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_OFF
#include<spdlog.h>
It is explained as a comment in the file https://github.com/gabime/spdlog/blob/v1.x/include/spdlog/spdlog.h :
//
// enable/disable log calls at compile time according to global level.
//
// define SPDLOG_ACTIVE_LEVEL to one of those (before including spdlog.h):
// SPDLOG_LEVEL_TRACE,
// SPDLOG_LEVEL_DEBUG,
// SPDLOG_LEVEL_INFO,
// SPDLOG_LEVEL_WARN,
// SPDLOG_LEVEL_ERROR,
// SPDLOG_LEVEL_CRITICAL,
// SPDLOG_LEVEL_OFF
//
Using this macro will also speed up your productive code because the logging calls are completely erased from your code. Therefore this approach may be better than using my_logger->set_level(spdlog::level::off);
However, in order for the complete code removal to work you need to use either of the macros when logging:
SPDLOG_LOGGER_###(logger, ...)
SPDLOG_###(...)
where ### is one of TRACE, DEBUG, INFO, WARN, ERROR, CRITICAL.
The latter macro uses the default logger spdlog::default_logger_raw(), the former can be used with your custom loggers. The variadic arguments ... stand for the regular arguments to your logging invocation: the fmt string, followed by some values to splice into the message.
I don't know spdlog.
However, you may define a macro in one of your common used include file, to replace the logcall by nothing, or a call to an empty inline function which the compiler optimizer will eliminate.
in "app.h"
#ifndef LOG
#ifdef logging
#define LOG spdlog
#endif
#ifndef logging
#define LOG noop
#endif
#endif
Did you get the idea?
This let most of your code untouched

C++ - Two names in class declaration (macros)

I'm working on existing C++ code, which is using a kind of API.
While browsing the code I found a strange syntax that I saw now for the first time and I can't figure out what it does or how such is called.
It goes like this:
class KINDA_API foobar : public foo {
// Some class declarations
};
Everything after foobar is understandable for me. But what means that KINDA_API? What does this do? Is that any kind of advanced derivation or something like that?
Maybe there is any other Thread that answers this, and I also searched for it, but I don't even know how this is called ^^'
Usually when you see OMGWFT_API declarations in this exact way, this is a 'magic switch' for building a library in correct "mode":
static linking - OMGWFT_API replaced by "" (empty string)
dynamic linking - DLL - OMGWFT_API replaced by declspec(dllexport)
dynamic linking - EXE - OMGWFT_API replaced by declspec(dllimport)
i.e.
#ifdef BUILD_ME_AS_STATICLIB
#define OMGWFT_API
#else
#ifdef BUILD_ME_AS_DLL
#define OMGWFT_API declspec(dllexport)
#else
#define OMGWFT_API declspec(dllimport)
#endif
#endif
This is of course just an sketch of example, but I think you get the point now. Keywords are taken from MSVC not GCC< because I accidentially happen to remember them.
The "BUILD_ME_AS...." macros would be then defined via project options or -D command line switch.
However, it the OMGWFT_API can be set to have any meaning, so be sure to grep/search for a #define that sets this.
I guess it is a #define-d macro that does some "magic" before compile.
If you look through the existing call you are likely to find somthing like:
#ifdef _WIN32
#define KINDA_API <windows specific attribute>
#elif __linux
#define KINDA_API <linux specific attribute>
etc...
These macros are more likely conditioned on compilers and/or their versions rather than operating system but you get the idea...

Debugging in C/C++: cost of calling an empty function

One normal procedure to implement debugging is the use of
#ifdef DEBUG
...debugging tests...
#endif
Sometimes, a typical "checking" algorithm is needed in some parts of the code, and so one would normally like to wrap it on a function, such that the code is only called when DEBUG flag is defined. Let that function be called myDebug();
I see two natural approaches for this: either ifdef is added on each time myDebug() is called, like this:
#ifdef DEBUG
myDebug();
#endif
Or myDebug is defined as:
void myDebug()
{
#ifdef DEBUG
...code...
#endif
}
Basically, the first avoids the function calling, while the second avoid putting the code with a lot of #ifdef/#endif.
Is there any "standard" convention to choose one of the two, or another way that I don't know? Is is worth to choose the second from the "styling" point of view?
Thanks
I'd go with number 3:
#ifdef DEBUG
#define myDebug(x) myDebug(x)
#else
#define myDebug(x) {}
#endif
This way, there's no pesky #ifdefs everywhere in the code, and for a non-debug build no code will be generated.

Per-file enabling of scope guards

Here's a little problem I've been thinking about for a while now that I have not found a solution for yet.
So, to start with, I have this function guard that I use for debugging purpose:
class FuncGuard
{
public:
FuncGuard(const TCHAR* funcsig, const TCHAR* funcname, const TCHAR* file, int line);
~FuncGuard();
// ...
};
#ifdef _DEBUG
#define func_guard() FuncGuard __func_guard__( TEXT(__FUNCSIG__), TEXT(__FUNCTION__), TEXT(__FILE__), __LINE__)
#else
#define func_guard() void(0)
#endif
The guard is intended to help trace the path the code takes at runtime by printing some information to the debug console. It is intended to be used such as:
void TestGuardFuncWithCommentOne()
{
func_guard();
}
void TestGuardFuncWithCommentTwo()
{
func_guard();
// ...
TestGuardFuncWithCommentOne();
}
And it gives this as a result:
..\tests\testDebug.cpp(121):
Entering[ void __cdecl TestGuardFuncWithCommentTwo(void) ]
..\tests\testDebug.cpp(114):
Entering[ void __cdecl TestGuardFuncWithCommentOne(void) ]
Leaving[ TestGuardFuncWithCommentOne ]
Leaving[ TestGuardFuncWithCommentTwo ]
Now, one thing that I quickly realized is that it's a pain to add and remove the guards from the function calls. It's also unthinkable to leave them there permanently as they are because it drains CPU cycles for no good reasons and it can quickly bring the app to a crawl. Also, even if there were no impacts on the performances of the app in debug, there would soon be a flood of information in the debug console that would render the use of this debug tool useless.
So, I thought it could be a good idea to enable and disable them on a per-file basis.
The idea would be to have all the function guards disabled by default, but they could be enabled automagically in a whole file simply by adding a line such as
EnableFuncGuards();
at the top of the file.
I've thought about many a solutions for this. I won't go into details here since my question is already long enough, but let just say that I've tried more than a few trick involving macros that all failed, and one involving explicit implementation of templates but so far, none of them can get me the actual result I'm looking for.
Another restricting factor to note: The header in which the function guard mechanism is currently implemented is included through a precompiled header. I know it complicates things, but if someone could come up with a solution that could work in this situation, that would be awesome. If not, well, I certainly can extract that header fro the precompiled header.
Thanks a bunch in advance!
Add a bool to FuncGuard that controls whether it should display anything.
#ifdef NDEBUG
#define SCOPE_TRACE(CAT)
#else
extern bool const func_guard_alloc;
extern bool const func_guard_other;
#define SCOPE_TRACE(CAT) \
NppDebug::FuncGuard npp_func_guard_##__LINE__( \
TEXT(__FUNCSIG__), TEXT(__FUNCTION__), TEXT(__FILE__), \
__LINE__, func_guard_##CAT)
#endif
Implementation file:
void example_alloc() {
SCOPE_TRACE(alloc);
}
void other_example() {
SCOPE_TRACE(other);
}
This:
uses specific categories (including one per file if you like)
allows multiple uses in one function, one per category or logical scope (by including the line number in the variable name)
compiles away to nothing in NDEBUG builds (NDEBUG is the standard I'm-not-debugging macro)
You will need a single project-wide file containing definitions of your category bools, changing this 'settings' file does not require recompiling any of the rest of your program (just linking), so you can get back to work. (Which means it will also work just fine with precompiled headers.)
Further improvement involves telling the FuncGuard about the category, so it can even log to multiple locations. Have fun!
You could do something similar to the assert() macro where having some macro defined or not changes the definition of assert() (NDEBUG in assert()'s case).
Something like the following (untested):
#undef func_guard
#ifdef USE_FUNC_GUARD
#define func_guard() NppDebug::FuncGuard __npp_func_guard__( TEXT(__FUNCSIG__), TEXT(__FUNCTION__), TEXT(__FILE__), __LINE__)
#else
#define func_guard() void(0)
#endif
One thing to remember is that the include file that does this can't have include guard macros (at least not around this part).
Then you can use it like so to get tracing controlled even within a compilation unit:
#define USE_FUNC_GUARD
#include "funcguard.h"
// stuff you want traced
#undef USE_FUNC_GUARD
#include "funcguard.h"
// and stuff you don't want traced
Of course this doesn't play 100% well with pre-compiled headers, but I think that subsequent includes of the header after the pre-compiled stuff will still work correctly. Even so, this is probably the kind of thing that shouldn't be in a pre-compiled header set.