In my VC++ project I use a macro for debugging and logging purpose.
calling:
Logger(LogLevel::Info, "logging started");
macro:
#ifdef DEBUG
#define Logger(level, input) \
{ \
cerr << "[" << level << "] " << input << endl; \
};
#else
#define Logger();
#endif
When compiling this I get the following warning (but it still compiles):
warning C4002: too many actual parameters for macro 'Logger'
I am wondering how the compiler handles this situation.
Are the macro parameters still used for compiling? E.g. will one be able to see the "logging started" string on reverse engeneering?
I am wondering how the compiler handles this situation. Are the macro parameters still used for compiling?
Macros are processed in the pre-processing stage. If the pre-processor is able to deal with the extra arguments used in the usage of the macro, the only thing it can do is drop those parameters in the macro expansion.
E.g. will one be able to see the "logging started" string on reverse engeneering?
No, the code processed by the compiler will not have that line at all.
If you have the option to change those lines of code, I would recommend changing the non-debug definition of the macro to be a noop expansion. E.g.:
#define Logger(level, input) (void)level;
As per the law, a macro function must declare as many parameters as you call it with.
So calling your macro
#define Logger()
as Logger(LogLevel::Info, "logging started") results in an error. MSVC probably allows it because it isn't standard-compliant. There's not much to reason further (which is my answer to the actual question).
You either
#define Logger(unused,unused2)
and leave the replacement part empty or
#define Logger(...)
and suffer the consequences of being able to call with any number of arguments. [Hint: First one is recommended.]
Related
I'm writing a logger module, so I would like to print the debug infos like __FILE__ and __LINE__ in c/c++. So I used macro function like:
/// here's just an example
/// function str_format() returns a std::string in format like printf() in c
#define info(str, ...) (cout << str_format(str, ##__VA_ARGS__) << __FILE__ << ":" << __LINE__)
in most cases, it works fine. but 'define' just has more influence than I thought.
to give an example, if a member variable in c++ class needs initialize:
class test{
private:
int info;
public:
test(int a) : info(a) {}
};
this would cause an unexpected error, the compiler would take info as a macro function!
even the header file of logger(which is logger.h) is not included in the class test's file, as long as the third file include them both, and include 'logger.h' before 'test.h' would cause this problem! that's really annoying.
So, is there any way other than #undef (since the test.h has nothing to with logger.h) to solve this problem? or let's say how can I get debug info like FILE without using macro function?
As far as __FILE__ and __LINE__ is concerned, C++20 introduced std::source_location for this. There is no equivalent non-macro based solution in prior C++ standards.
As far as a non-macro logging solution overall, the most common approach involves implementing the logging function as a variadic template with a parameter pack, that ends up formatting the log message, from its parameters.
No, there is no other way. You'll have to either not use file information (really, who cares what your file is called? Most likely you actually care about the call stack at a problem location, which is what exceptions give you) or use better names than info. In fact the convention for macros is to use all caps, like INFO.
Trying to determine a "modern" implementation for the following C-style code:
#define logError(...) log(__FILE__, __LINE__, __VA_ARGS__)
Is is possible to capture this using variadic templates or something similar that does not rely on a #define ?
Desired use case:
logError( "Oh no! An error occurred!" );
Where __FILE__, and __LINE__ are captured under the hood, but reflect the file name and line number of where logError was called from.
Macros are indeed your only choice, at least until std::source_location makes it into the standard and fulfills your wish.
Actually the preprocessor is the only choice when you want to work with line numbers and filenames.
For the compiler it's not possible to use line numbers and filenames as arguments for function calls (or storing them in a variable).
In my company we had the exactly same issue with logging. We ended up with an external script scanning the source files and then building proper functions to call.
Is there a "best practice" or similar for coding in a debug-mode in one's code?
For example,
#include <iostream>
int main()
{
#ifdef MY_DEBUG_DEF
std::cout << "This is only printed if MY_DEBUG_DEF is defined\n";
#endif
return 0;
}
Or is this considered bad practice because the code gets bit messier?
I have noticed some libraries (for example libcurl, which is a large and well-known library) have this feature; if you define VERBOSE with libcurl you get basically a debug mode
Thank you.
A more usual way is to follow conventions from assert(3): wrap with #ifndef NDEBUG .... #endifcode which is only useful for debugging, and without any significant side effects.
You could even add some debug-printing macro like
extern bool wantdebug;
#ifndef NDEBUG
#define OUTDEBUG(Out) do { if (wantdebug) \
std::cerr << __FILE__ << ":" << __LINE__ \
<< " " << Out << std::endl; \
} while(0)
#else
#define OUTDEBUG(Out) do {}while(0)
#endif
and use something like OUTDEBUG("x=" << x) at appropriate places in your code. Then wantdebug flag would be set thru the debugger, or thru some program arguments. You probably want to emit a newline and flush cerr (or cout, or your own debug output stream) -using std::endl ...- to get the debug output displayed immediately (so a future crash of your program would still give sensible debug outputs).
That is an acceptable method. Yes, it gets messy, but it makes it a lot easier to debug as well. Plus you can normally collapse those kinds of things, thus removing the messiness.
As you've mentioned, libcurl uses the method. I also used to have a teacher who works for HP on their printer software, and they used the same method.
I personally prefer runtime enabled logging. That means that you don't have to recompile to get the "debug output". So I have a command-line argument -v=n, where n defaults to zero, and gets stored in the variable verbosity in the actual program. With -v=1 I get basic tracing (basic flow of the code), with -v=2 I get "more stuff" (such as dumps of internal state in selected functions). Two levels is often enough, but three levels may be good at times. An alternative is to make verbosity a bit-pattern, and enable/disable certain functionality based on which bits are set - so set bit 0 for basic trace, bit 1 gives extra info in some module, bit 2 gives extra trace in another module, etc. If you want to be REALLY fancy, you have names, such as -trace=all_basic, -trace=detailed, -trace=module_A, -trace=all_basic,module_A,module_B or some such.
Combine this with a macro along the lines of:
#define TRACE do { if (verbosity > 0) \
std::cout << __FILE__ << ":" << __LINE__ << ":" \
<< __PRETTY_FUNCTION__ << std::endl; } while(0)
For things that may take a substantial amount of extra time, such as verifying the correctness of a large and complex data structure (tree, linked list, etc), then using #ifndef NDEBUG around that code would be a good thing. Assuming of course you believe that you'll never mess that up in a release build.
Real livig code here:
https://github.com/Leporacanthicus/lacsap/blob/master/trace.h
https://github.com/Leporacanthicus/lacsap/blob/master/trace.cpp
being use here for example:
https://github.com/Leporacanthicus/lacsap/blob/master/expr.cpp
(Note that some simple functions that get called a lot don't have "TRACE" - it just clutters up the trace and makes it far too long)
Using logger may be better, e.g.
log4cxx
log4cpp
ACE_Log_Msg: It is in ACE
Boost.Log:
The above are very flexible, but heavyweight. You can also implement some simple macros instead:
#ifdef NDEBUG
#define DBG(FMT, ...)
#else // !NDEBUG
#define DBG(FMT, ...) fprintf (stderr, FMT, ## __VA_ARGS__)
#endif // NDEBUG
The above is GCC syntax from Macros with a Variable Number of Arguments.
For VC, please see also How to make a variadic macro (variable number of arguments)
I'd like to have the possibility to increase the verbosity for debug purposes of my program. Of course I can do that using a switch/flag during runtime. But that can be very inefficient, due to all the 'if' statements I should add to my code.
So, I'd like to add a flag to be used during compilation in order to include optional, usually slow debug operations in my code, without affecting the performance/size of my program when not needed. here's an example:
/* code */
#ifdef _DEBUG_
/* do debug operations here
#endif
so, compiling with -D_DEBUG_ should do the trick. without it, that part won't be included in my program.
Another option (at least for i/o operations) would be to define at least an i/o function, like
#ifdef _DEBUG_
#define LOG(x) std::clog << x << std::endl;
#else
#define LOG(x)
#endif
However, I strongly suspect this probably isn't the cleanest way to do that. So, what would you do instead?
I prefer to use #ifdef with real functions so that the function has an empty body if _DEBUG_ is not defined:
void log(std::string x)
{
#ifdef _DEBUG_
std::cout << x << std::endl;
#endif
}
There are three big reasons for this preference:
When _DEBUG_ is not defined, the function definition is empty and any modern compiler will completely optimize out any call to that function (the definition should be visible inside that translation unit, of course).
The #ifdef guard only has to be applied to a small localized area of code, rather than every time you call log.
You do not need to use lots of macros, avoiding pollution of your code.
You can use macros to change implementation of the function (Like in sftrabbit's solution). That way, no empty places will be left in your code, and the compiler will optimize the "empty" calls away.
You can also use two distinct files for the debug and release implementation, and let your IDE/build script choose the appropriate one; this involves no #defines at all. Just remember the DRY rule and make the clean code reusable in debug scenario.
I would say that his actually is very dependent on the actual problem you are facing. Some problems will benefit more of the second solution, whilst the simple code might be better with simple defines.
Both snippets that you describe are correct ways of using conditional compilation to enable or disable the debugging through a compile-time switch. However, your assertion that checking the debug flags at runtime "can be very inefficient, due to all the 'if' statements I should add to my code" is mostly incorrect: in most practical cases a runtime check does not influence the speed of your program in a detectable way, so if keeping the runtime flag offers you potential advantages (e.g. turning the debugging on to diagnose a problem in production without recompiling) you should go for a run-time flag instead.
For the additional checks, I would rely on the assert (see the assert.h) which does exactly what you need: check when you compile in debug, no check when compiled for the release.
For the verbosity, a more C++ version of what you propose would use a simple Logger class with a boolean as template parameter. But the macro is fine as well if kept within the Logger class.
For commercial software, having SOME debug output that is available at runtime on customer sites is usually a valuable thing to have. I'm not saying everything has to be compiled into the final binary, but it's not at all unusual that customers do things to your code that you don't expect [or that causes the code to behave in ways that you don't expect]. Being able to tell the customer "Well, if you run myprog -v 2 -l logfile.txt and do you usual thing, then email me logfile.txt" is a very, very useful thing to have.
As long as the "if-statement to decide if we log or not" is not in the deepest, darkest jungle in peru, eh, I mean in the deepest nesting levels of your tight, performance critical loop, then it's rarely a problem to leave it in.
So, I personally tend to go for the "always there, not always enabled" approach. THat's not to say that I don't find myself adding some extra logging in the middle of my tight loops sometimes - only to remove it later on when the bug is fixed.
You can avoid the function-like macro when doing conditional compilation. Just define a regular or template function to do the logging and call it inside the:
#ifdef _DEBUG_
/* ... */
#endif
part of the code.
At least in the *Nix universe, the default define for this kind of thing is NDEBUG (read no-debug). If it is defined, your code should skip the debug code. I.e. you would do something like this:
#ifdef NDEBUG
inline void log(...) {}
#else
inline void log(...) { .... }
#endif
An example piece of code I use in my projects. This way, you can use variable argument list and if DEBUG flag is not set, related code is cleared out:
#ifdef DEBUG
#define PR_DEBUG(fmt, ...) \
PR_DEBUG(fmt, ...) printf("[DBG] %s: " fmt, __func__, ## __VA_ARGS__)
#else
#define PR_DEBUG(fmt, ...)
#endif
Usage:
#define DEBUG
<..>
ret = do_smth();
PR_DEBUG("some kind of code returned %d", ret);
Output:
[DBG] some_func: some kind of code returned 0
of course, printf() may be replaced by any output function you use. Furthermore, it can be easily modified so additional information, as for example time stamp, is automatically appended.
For me it depends from application to application.
I've had applications where I wanted to always log (for example, we had an application where in case of errors, clients would take all the logs of the application and send them to us for diagnostics). In such a case, the logging API should probably be based on functions (i.e. not macros) and always defined.
In cases when logging is not always necessary or you need to be able to completely disable it for performance/other reasons, you can define logging macros.
In that case I prefer a single-line macro like this:
#ifdef NDEBUG
#define LOGSTREAM /##/
#else
#define LOGSTREAM std::clog
// or
// #define LOGSTREAM std::ofstream("output.log", std::ios::out|std::ios::app)
#endif
client code:
LOG << "Initializing chipmunk feeding module ...\n";
//...
LOG << "Shutting down chipmunk feeding module ...\n";
It's just like any other feature.
My assumptions:
No global variables
System designed to interfaces
For whatever you want verbose output, create two implementations, one quiet, one verbose.
At application initialisation, choose the implementation you want.
It could be a logger, or a widget, or a memory manager, for example.
Obviously you don't want to duplicate code, so extract the minimum variation you want. If you know what the strategy pattern is, or the decorator pattern, these are the right direction. Follow the open closed principle.
Im trying to make a generic function to display error messages, with the possibility that the program should exit after the message has been displayed.
I want the function to show the source file and line at which the error occurred.
argument list:
1.char *desc //description of the error
2.char *file_name //source file from which the function has been called
3.u_int line //line at which the function has been called
4.bool bexit=false //true if the program should exit after displaying the error
5.int code=0 //exit code
Because of (4) and (5) i need to use default arguments in the function definition, since i don't want them to be specified unless the program should exit.
Because of (2) and (3) i need to use a macro that redirects to the raw function, like this one:
#define Error(desc, ???) _Error(desc,__FILE,__LINE__, ???)
The problem is that i don't see how those 2 elements should work together.
Example of how it should look like:
if(!RegisterClassEx(&wndcls))
Error("Failed to register class",true,1); //displays the error and exits with exit code 1
if(!p)
Error("Invalid pointer"); //displays the error and continues
You cannot overload macros in C99 -- you will need two different macros. With C11, there is some hope using _Generic.
I had developed something very similar -- a custom warning generator snippet for Visual Studio -- using macros. GNU GCC has some similar settings for compatibility with MSVS.
#define STR2(x) #x
#define STR1(x) STR2(x)
#define LOC __FILE__ “(“STR1(__LINE__)”) : Warning Msg: “
#define ERROR_BUILDER(x) printf(__FILE__ " (“STR1(__LINE__)”) : Error Msg: ” __FUNCTION__ ” requires ” #x)
The above lines take care of your arguments 1 to 3. Adding support for 4 would require inserting a exit() call within the macro. Also, create two different macro wrappers should you require to two different argument lists (the one with the default argument can delegate to the other macro).
#define ERROR_AND_EXIT(msg, cond, errorcode) ERROR_BUILDER(msg) if (cond) exit(errorcode)
#define ERROR_AND_CONT(msg) ERROR_BUILDER(msg)
I had put up a detailed description here (warning: that's my blog -- so consider it to be a shameless plug).