I'm writing a logging class at the moment. The Logger works with streams and also prints the object which is logging at the moment. Here is the macro:
#define OBJLOG(DL, what) DL <= this->Logger->getDebugLevel() ? *this->Logger << DL << "[" << this->Name << "]: "<< what << std::endl : this->Logger->doNothing();
The pseudo code Variant for better overview:
#define OBJLOG(debuglevel, what) debuglevel <= logger.debuglevel ? logger.log(what) : logger.doNothing()
Is there any way to get around the doNothing function call, like doing nothing at all?
#define OBJLOG(DL, what) do { if(DL <= this->Logger->getDebugLevel()) *this->Logger << DL << "[" << this->Name << "]: "<< what << std::endl; } while(0)
See Why use apparently meaningless do-while and if-else statements in macros? for an explanation. (The do {} while(0) isn't strictly necessary here, but I would prefer not to leak an ostream.)
Also, you should always wrap macro argument uses in parentheses, like:
#define OBJLOG(DL, what) do { if((DL) <= this->Logger->getDebugLevel()) *this->Logger << (DL) << "[" << this->Name << "]: "<< (what) << std::endl; } while(0)
Finally, you should move this code into a function and call that in your macro (if you really insist on using a macro) to avoid evaluating your macro arguments more than once.
Have your logger.log() function return a boolean.
Connect your predicates with an and like this: debuglevel <= logger.debuglevel && logger.log
That should do the trick.
If you want an expression that does nothing, try (void)0.
Related
In the C++ library glog (Google logging module) there is a nice interface where you can write
LOG(INFO) << "abc " << my_var;
and at runtime it prints something like abc 5\n at runtime (if my_var was 5) where it automatically terminated with a newline.
This is much superior to having to always terminate with std::endl as in
std::cout << "abc " << my_var << std::endl;
What is the simpliest way (code + macros) do I need to replicate this effect in my code?
I think the idea is to return a temp wrapper object:
#include <iostream>
struct Log
{
~Log(void) { ::std::cout << ::std::endl; }
};
template<typename T> Log &&
operator <<(Log && wrap, T const & whatever)
{
::std::cout << whatever;
return ::std::move(wrap);
}
int main()
{
Log() << "whatever";
Log() << "more";
return 0;
}
online compiler
Note that the macro can be used here to execute conditional branching in the beginning of logging. That is skip logging if severity level is low.
#define LOG(level) \
if(g_log_lelevel <= level) Log()
Some time ago, I made this beautiful assert macro for c and c++ programs
#define ASSERT(truthy, message) \
if (!(truthy)) \
{\
cout << message << " on line " << __LINE__ << " in file " << __FILE__ << ". Check was " << #truthy << endl;\
}
Scatter ASSERT calls throughout your code, and it will warn you whenever the truthy value is not truthy! Very handy during development to remind you of potential mistakes.
ex
ASSERT(filesFound > 0, "Couldn't find any files, check your path!");
When filesFound is 0, the macro will print out
Couldn't find any files, check your path! on line 27 in file
openFiles.c. Check was filesFound > 0
Now what I want it to print, to give me even more relevant information, is the value of any variables passed into the truthy parameter. Like this
Couldn't find any files, check your path! on line 27 in file
openFiles.c. Check was filesFound > 0, filesFound is 0
This seems lisp-like territory, I wonder, is there any black magic c preprocessing that I can use to evaluate variables and functions to their values, without evaluating the truthy statement?
I assume to be disappointed.
An alternative solution which I've always used is to support varargs in the macro and then force the assert user to specify the relevant message / variables - it's a little bit of extra work each time, but on the plus side you can get exactly the formatting that you want and include information not available in the "truthy" bit, e.g:
#define ASSERT(truthy, message, ...) \
if (!(truthy)) \
{\
MyAssertHandler(__LINE__, __FILE__, #truthy, message, ##__VA_ARGS__);
}
Then you're handler is just a fairly standard var-arg function that can use e.g. vsnprintf to generate the message and output it, e.g. off the top of my head:
void MyAssertHandler(int line, const char* file, const char* expressionStr, const char* format, ...)
{
// Note: You probably want to use vsnprintf instead to first generate
// the message and then add extra info (line, filename, etc.) to
// the actual output
va_list args;
va_start(args, format);
vprintf(format, args);
va_end(args);
// Log to bug database, DebugBreak() if a debugger is attached, etc.
}
usage:
ASSERT(IsBlah(), "BlahBlah: x = %.2f, name = %s", GetX(), GetName());
I cannot imagine a way to do it... except by passing another parameter
#define ASSERT_PARAM(truthy, message, param) \
if (!(truthy)) \
{\
cout << message << " on line " << __LINE__ << " in file " << __FILE__ << ". Check was " << #truthy << ", value was " << param << endl;\
}
You would use it that way:
ASSERT_PARAM(filesFound > 0, "Couldn't find any files, check your path!", filesFound);
getting:
Couldn't find any files, check your path! on line 27 in file openFiles.c. Check was filesFound > 0, value was 0
What you are trying to do sounds very complicated. I'm afraid in C++ it's not possible.
Technically what you are evaluating is a bool expression so you can pass it to a parser whenever the assertion fails. The parser then will build the expression tree, get the leaves (elements of the expression) and return them. The returned values then should be printed out. To do that you will need support for reflection which is actually not supported in C++ AFAIK.
Maybe not the dream solution, but you can pass whole statements to a macro.
#define ASSERT(trusty, action) if (!trusty) { action }
ASSERT(trusty, cout << a << b;)
ASSERT(trusty, printf("%d, %f\n", a, b);)
I think you can split up the truthy Expression like they do it in the first answer here and then you can probably print the individual values. But I'm not sure if it actually works.
The printing could then be resulved using a variadic template function
Perhaps you could compromise and only allow 2 variables and 1 operator in the assertion expression? If so, you could make an ad hoc solution like this:
#include <iostream>
#include <string>
#define STRINGIFY(x) #x
#define BIN_ASSERT(obj1, op, obj2, msg) \
if(!(obj1 op obj2)) \
{ \
std::cout << msg << " on line " << __LINE__ \
<< " in file " << __FILE__ \
<< "." << std::endl \
<< "Check was " \
<< STRINGIFY(obj1) STRINGIFY(op) STRINGIFY(obj2) \
<< "." << std::endl \
<< "Operator " << #obj1 << ": " << obj1 \
<< "." << std::endl \
<< "Operator " << #obj2 << ": " << obj2 \
<< "." << std::endl; \
}
int main (void)
{
int x = 2;
int y = 3;
std::string s1 = "hello";
std::string s2 = "world";
BIN_ASSERT(1, +, -1, "Value zero"); std::cout << std::endl;
BIN_ASSERT(x, ==, y, "Numbers not equal"); std::cout << std::endl;
BIN_ASSERT(s1, ==, s2, "Strings not equal"); std::cout << std::endl;
}
Output:
Value zero on line 30 in file test.c.
Check was 1+-1.
Operator 1: 1.
Operator -1: -1.
Numbers not equal on line 31 in file test.c.
Check was x==y.
Operator x: 2.
Operator y: 3.
Strings not equal on line 32 in file test.c.
Check was s1==s2.
Operator s1: hello.
Operator s2: world.
I wonder if having the macro take a message is really that useful. A failed assertion is a message to the developer that there is a bug in the code that caused an exceptional behaviour or put the program in an unacceptable state. The user has less to do with it (if they even have access to the source code).
The code below defines an ASSERT macro that takes a boolean expression, evaluates it and prints an informational message. The message contains a value that you've asked to inspect upon failing the assertion.
The macro, just like the standard assert() macro (in <cassert>) goes on to call abort() (from <cstdlib>) to cause an abnormal program termination. This is what you want, because the program entered a state in which it didn't know what more to do.
I'm using std::printf() here for brevity. You do whatever you want.
#include <cstdlib>
#include <cstdio>
#define ASSERT(value, inspect) \
if (!(value)) { \
std::printf("ASSERTION FAILED: '%s', %s is %d: %s#%s:%d\n", #value, \
#inspect, inspect, __func__, __FILE__, __LINE__); \
abort(); \
}
int foo() { return 42; }
int main()
{
// ...
ASSERT(foo() - 40 == 1, foo());
//...
}
Program run:
$ ./a.out
ASSERTION FAILED: 'foo() - 40 == 1', foo() is 42: main#prog.cc:16
Abort
It's not possible to do exactly what you ask for without adding more parameters to the macro. At some point you'll have to stop and realize that you're spending time on creating a text string that you do not want to see.
You need to build an expression 'grabber' / builder.
The macro would become something like:
#define ASSERT_PARAM(truthy, message, param) \
if (!(truthy)) \
{\
Grabber g;
g << #truthy; // grab expression as string
g % truthy; // grab expression and values
cout << message << " on line " << __LINE__ << " in file " << __FILE__ << ". Check was " << #truthy << ", value was " << param << endl;\
cout << g; \
}
What does Grabber do?
It is a bunch of crazy C++ that builds up an expression. It would overload every operator to 'grab' the params of the operator. Every operator returns a reference to the grabber, so it can grab the next operator. ie
Grabber g;
g % filesFound > 0;
Since % (and * and /) have high precedence, the above parses like:
((g % filesFound) > 0)
If template<typename T> Grabber::operator%(T const & val) just records (or prints) the value passed in (ie filesFound), and - importantly - returns itself (g) so that it becomes part of the next expression: ie it becomes g > 0. Causing template<typename T> Grabber::operator>(T const & val) to be called, and > 0 to be recorded.
Then cout << g can spew out everything grabbed.
As mentioned above "It is possible — the Catch library does it. But it’s hellishly difficult".
P.S. you should wrap your macro in a do ... while 0 like this:
#define ASSERT_PARAM(truthy, message, param) \
do \
{ \
if (!(truthy)) \
{\
cout << message << " on line " << __LINE__ << " in file " << __FILE__ << ". Check was " << #truthy << ", value was " << param << endl;\
cout << g; \
} \
} while (0)
What you have currently means that this is valid code:
ASSERT(foo != 0)
else
{
}
And this is NOT valid code:
if (foo != nullptr)
ASSERT(foo->bar != nullptr);
else
x = 10;
Surprisingly, I solved a similar problem before, but I'm not sure if it could help you in this case.
The original solution was proposed by Andrei Alexandrescu in the article Enhancing Assertions, and with no question, relying on some macro tricks.
This amazing facility can be used as the following:
string s1, s2;
...
SMART_ASSERT(s1.empty() && s2.empty())(s1)(s2);
And if something goes wrong, the message would be displayed
Assertion failed in matrix.cpp: 879412:
Expression: 's1.empty() && s2.empty()'
Values: s1 = "Wake up, Neo"
s2 = "It's time to reload."
Be noted that, the SMART_ASSERT can capture infinite variables, theoretically.
For implementation details, please check out the article.
In the absence of help from Google, I wonder if someone could tell me if it is possible to create a C++ (g++) debug macro that acts like, for example, an "improved" std::cout. Idea is to accept args via << and to append some text so that
DBG << "Hello" << world;
might produce
myfile.cpp 1420 Hello world
I know there are logging libraries(?)/macros(?) out there that do this sortof thing. I'm interested in how it's done, not using some package.
Your macro could create a temporary variable which invokes endl on destruction. The temporary will stick around until the enclosing expression ends, typically at the ;.
#include <iostream>
struct X {
~X() { std::cout << std::endl; }
};
#define DBG (X(), std::cout << __FILE__ << " " << __LINE__ << " ")
int main () {
std::string world(", world");
DBG << "Hello" << world;
}
How about:
#define DBG std::cout << __FILE__ << " " << __LINE__ << " "
http://ideone.com/mN5n3
Close enough! Unfortunatelly, you have to declare the variable world beforehand.
The idea behind a debug macro is that it should compile to nothing if you are in release mode. Try this;
#ifdef _DEBUG
#define MESSAGE(x) (std::cout << __FILE__ << " " << __LINE__ << " " << x);
#else
#define MESSAGE(x) ;
#endif
int _tmain(int argc, _TCHAR* argv[])
{
MESSAGE("Hello");
return 0;
}
When you are in release mode, MESSAGE(x) will have no effect, but in debug mode, you will get a message to the command line.
my_macro << 1 << "hello world" << blah->getValue() << std::endl;
should expand into:
std::ostringstream oss;
oss << 1 << "hello world" << blah->getValue() << std::endl;
ThreadSafeLogging(oss.str());
#define my_macro my_stream()
class my_stream: public std::ostringstream {
public:
my_stream() {}
~my_stream() {
ThreadSafeLogging(this->str());
}
};
int main() {
my_macro << 1 << "hello world" << std::endl;
}
A temporary of type my_stream is created, which is a subclass of ostringstream. All operations to that temporary work as they would on an ostringstream.
When the statement ends (ie. right after the semicolon on the whole printing operation in main()), the temporary object goes out of scope and is destroyed. The my_stream destructor calls ThreadSafeLogging with the data "collected" previously.
Tested (g++).
Thanks/credits to dingo for pointing out how to simplify the whole thing, so I don't need the overloaded operator<<. Too bad upvotes can't be shared.
Couldn't you just derive from ostream and provide your own thread safe implementation? Then you could just do
myCOutObject << 1 << "hello world" << blah->getValue() << std::endl;
And get the exact same functionality without macros and using C++ properly?
No. The problem is that without using function syntax, a macro is limited to only being replaced where it is.
But if you were willing to use function syntax, you can then replace stuff both before and after the args.
my_macro(1 << "hello world" << blah->getValue() << std::endl);
You could by defining MyMacro as:
#define my_macro(args) std::ostreamstring oss; \
oss << args; \
ThreadSafeLogging(oss.str());
Take a look at google-glog, they do this using a temporary object instanciated with a
LOG(INFO) << "log whatever" << 1;
and they also have other interesting macros such as LOG_IF et al.
Considering you have these lines included somewhere in your code, yes it is possible
#include <iostream>
#include <sstream>
__LINE__ macro is defined by all standart compilers.
So we can use it to generate a variable name wich is different each time you use the macro :)
Here is a new version that is seen as a one-statement instruction only:
(EDITED)
#define Var_(Name, Index) Name##Index
#define Var(Name, Index) Var_(Name, Index)
#define my_macro \
for (struct { int x; std::ostringstream oss; } Var(s, __LINE__) = { 0 }; \
Var(s, __LINE__).x<2; ++Var(s, __LINE__).x) \
if (Var(s, __LINE__).x==1) ThreadSafeLogging(Var(s, __LINE__).oss.str()); \
else Var(s, __LINE__).oss
// So you can use it like this
int main()
{
if (4 != 2)
my_macro << 4 << " hello " << std::endl;
my_macro << 2 << " world !" << std::endl;
}
Developper probably won't need to use this macro twice on same line becasue of simplicity of operator <<. But in case you need this, you can switch the use of __LINE__ by __COUNTER__ (which is non standard!). Thanks to Quuxplusone for this tip
Here's another nasty trick I saw somewhere else. It has a significant disadvantage compared to my other answer: you can't use it twice in the same scope because it declares a variable. However, it may still be interesting for other cases where you want to have somemacro foo run something after foo.
#define my_macro \
std::ostringstream oss; \
for (int x=0; x<2; ++x) \
if (x==1) ThreadSafeLogging(oss.str()); \
else oss
int main() {
my_macro << 1 << "hello world" << std::endl;
}
The logging setup I have is quite similar:
bool ShouldLog(const char* file, size_t line, Priority prio);
class LoggerOutput : public std::stringstream {
public:
LoggerOutput(const char* file, size_t line, Priority prio)
: prio(prio)
{
Prefix(file, line, prio);
}
void Prefix(const char* file, size_t line, Priority prio);
~LoggerOutput() {
Flush();
}
void Flush();
private:
Priority prio;
};
#define LOG(Prio) if (!Logging::ShouldLog(__FILE__, __LINE__, Prio)) {} else Logging::LoggerOutput(__FILE__, __LINE__, Prio)
If your logging is disabled, the ostream is never created and little overhead exists. You can configure logging on file name & line number(s) or priority levels. The ShouldLog function can change between invocations, so you could throttle or limit output. The log output uses two functions to modify itself, Prefix that adds a "file:line: (PRIO) " prefix to the line, and Flush() which both flushes it to the log output as a single command and adds a newline to it. In my implementation it always does, but you can make that conditional if one is not already there.
I'm basically looking for a way to automate typing stuff like the following:
cout << "a[" << x << "][" << y << "] =\t" << a[x][y] << endl;
Something like:
PRINTDBG(a[x][y]);
Ideally this would also work for
PRINTDBG(func(arg1, arg2));
and even
PRINTDBG(if(condition) func(foo););
(which would print e.g. "if(false) func(5)").
Nonportable hacks welcome too :)
(no, using a debugger isn't the same, it's much less flexible and I find it confusing)
This is, in the way you want it, not possible. If you have if(condition) func(foo); given to a macro, it can stringize that stuff, and it will print if(condition) func(foo);, but not with the actual values of the variables substituted. Remember the preprocessor doesn't know about the structure about that code.
For debugging, i would use some type-safe printf variant like boost.format or some home brew printf with boost.fusion, which make the job of printing stuff like that much more easy:
dprintf("a[%][%] = %", (x, y, a[x][y]));
This is an area where the printf style output can be more concise:
cout << "a[" << x << "][" << y << "] =\t" << a[x][y] << endl;
printf("a[%d][%d] =\t%d\n", x, y, a[x][y]);
Of course, this has the limitation of only working for types that printf understands, and it still doesn't address your question.
I get the feeling that there might be something of value in the expression decomposition techniques in Boost, but I am not enough of a template ninja to identify what.
Update: The following almost addresses your question:
#define PRINTDBG(x) cout << #x << " =\t" << x << endl;
However, when used as PRINTDBG(a[x][y]) it literally prints:
a[x][y] = 5
which doesn't give the actual values of x and y.
I typically use a simple, but customizable logger function instead of macros
Log(const char *format, ...)
{
char buffer[MAX_BUFFER_SIZE];
va_list args;
//get arguements into a list
va_start(args, format);
//printf formated arguement into a string
vsnprintf(buffer, sizeof(buffer), format, args);
va_end(args);
printf("%s", buffer);
}
so now you can do
Log("a[%d][%d] =\t%d\n", x, y, a[x][y])
Log("if(%s) func(%d) ;", (condition) ? "true" : "False", func(foo))
add in some loggingtype (i.e. LOG_SCREEN, LOG_FILE) to the function Log() and now you can control where is gets logged to
add in some logginglevel (i.e. WARN, CRIT) to control how it gets displayed, color etc.
Of course there are many, many library's out there that do all this type of stuff already
hope this helps
In a slight expansion in a different direction to Greg's posting, I've seen some nice C programs that look something like this
#DEFINE DEBUG_MODE 1
//...
if( DEBUG_MODE)
printf("methodX() says: y=%i, var1=%i", y, var1);
However you still have a ton of printf's in your program, but at least you can turn them all on and off when you want to.
you can define operator« for custom classes so you only have to define formatting once:
struct point3 {
int x,y,z;
point3(int a, int b, int c){x=a;y=b;z=c;}
};
std::ostream& operator << (std::ostream& os, const point3& f) {
return os << "(" << f.x << "," << f.y << "," << f.z << ")";
}
point3 p(1,2,3);
std::cout << p; // prints "(1,2,3)"
this pairs well with redirecting cout or clog to a file (don't recall how std::clog works)
#include <iostream>
#include <fstream>
int main() {
std::ofstream file("log.txt");
std::streambuf *filebuf = file.rdbuf();
std::cout.rdbuf(filebuf);
std::cout << "This is written to the file";
filestr.close();
return 0;
}