I would like to concatenate the 3 following strings to produce a good debug output, by using std::setw() after.
__ FILENAME__ , ":" and LINE
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
#define AT __FILENAME__ ":" __LINE__
#ifdef DEBUG
#ifdef VERBOSE
#define printDebug(x) std::cout << AT << x << std::flush
#else
#define printDebug(x) std::cout << x << std::flush
#endif
#else
#define printDebug(x)
#endif
But actually I receive errors saying that a ";" field is missing before ":". Does someone have an idea ?
I actually call the printDebug() function like that :
printDebug("[SUCCESS] Receiving Message");
You can concatenate string literals by putting them alongside each other.
":" is a string literal.
__LINE__ expands to a numeric literal, not string one.
__FILENAME__ doesn't expand to a literal at all. It expands to an expression.
There is a way to get a string literal out of __LINE__, but you can't make __FILENAME__ a string literal.
You don't need to use literal concatenation here at all. You can simply do this:
#ifdef VERBOSE
#define printDebug(x) std::cout << __FILENAME__ << ":" << __LINE__ << x << std::flush
Related
This question already has answers here:
Convert a preprocessor token to a string
(6 answers)
Closed last year.
In C++ (or C) how can I get the line number (__LINE__) as a string?
In particular, I want a macro that magically has "example.cpp:14" on line 14 of example.cpp. C++ automatically combines juxtaposed string literals, so I just need __LINE__ as a string.
The trick to turning numerical constants into strings is the STR and XSTR macros, defined below:
#include <iostream>
//! See https://gcc.gnu.org/onlinedocs/cpp/Stringizing.html
#define XSTR(a) STR(a)
#define STR(a) #a
#define LINE_AS_STR XSTR(__LINE__)
#define FILE_AND_LINE __FILE__ ":" LINE_AS_STR
int main() {
constexpr const char* line = LINE_AS_STR;
std::cout << "That was line \"" << line << "\"" << std::endl;
std::cout << FILE_AND_LINE << std::endl;
}
output:
That was line "11"
example.cpp:13
https://godbolt.org/z/xzE1nWeMd
I would like to make single string from __FILE__, __FUNCTION__, and __LINE__ predefined macros.
#define LOG_LINE __FILE__ " " __FUNCTION__ " " __LINE__
This probably will don't work because compiler concat don't work with integers which __LINE__ is.
#define LOG_LINE __FILE__ __FUNCTION__
also don't work, because:
error: expected ';' before '__FUNCTION__'
How to achieve that to have
std::cout << LOG_LINE which will expand to e.g. main.cpp main 8?
Solution:
#define LOG_LINE __FILE__ << " " << __FUNCTION__ does not satisfy me because sometimes I would like to use it as string (big macro with sstream also is not valid solution ;).
You may use the following:
#define LOG_LINE (std::string(__FILE__ " ") + __FUNCTION__ + " " + std::to_string(__LINE__))
Live example
How do I get the text of the data given to value, not the value of the executed expression?
#define PRINT_VALUE(value) std::cout << "Value " << __RAWTEXT(value) << " is " << value << "\n";
__RAWTEXT is something I made up. Is there really something out there that does this though?
int testVariable = 5;
PRINT_VALUE(testVariable);
The output of this should be
Value testVariable is 5
Use the "stringize" operator # for this:
#define PRINT_VALUE(value) std::cout << "Value " << #value << " is " << value << "\n";
It's pretty straightforward, #TTT in a macro converts TTT to "TTT", a string literal.
It's worth mentioning that when the parameter is itself a macro, you'll get the name of the macro. However, if the parameter is passed to a subsequent macro, it's "unpacked". So you see these sometimes:
#define STRINGIZE2(X) #X
#define STRINGIZE(X) STRINGIZE2(X)
Here they are in action:
#define TEST Bob
std::cout << #TEST; //results in "TEST"
std::cout << STRINGIZE2(TEST); //results in "TEST"
std::cout << STRINGIZE(TEST); //results in "Bob"
Not relevent to your question but also notable is the "concat" macro operator ## which "glues" two bits of text togeather. std::st ## ing results in std::string. Useful in macros:
#define make_thing(X) \
structX##_class {
static const char* const name=#X;
};
make_thing(Foo);
std::cout << Foo_class::name;
And again, if a parameter is a macro, you get the macro name. So here's the de-macro macros:
#define GLUE2(X,Y) (X##Y)
#define GLUE(X,Y) GLUE2(X,Y)
#define HEY "HELLO"
#define THERE "WORLD"
std::cout << GLUE(HEY,THERE); //"HELLOWORLD"
I'm writing a simple macro to show TRACE information.
This is what I'm using ,
#ifdef __DEBUG__
#define TRACE { PrintErrorMsg("Trace exception at " __FILE__ "LineNo:"##(__LINE__) "Function: " __FUNCTION__ " " );}
#else
#define TRACE
#endif
This is working with FILE, but it doesn't seems to work with LINE ,
Any idea how could I deal with this. I already tried stringing operator too.Which is as
bellow.
#ifdef __DEBUG__
#define TRACE { PrintErrorMsg("Trace exception at " __FILE__ "LineNo:"#(__LINE__) "Function: " __FUNCTION__ " " );}
#else
#define TRACE
#endif
and without parms and with double parms , ex - __LINE__ or ((__LINE__))
Any idea how could I deal with this problem?
And I come up with this,
#ifdef __DEBUG__
#define ERROR_MSG_BUF_SIZE 1024
#define TRACE { char * error_msg_buffer = new char[ERROR_MSG_BUF_SIZE]; \
sprintf(error_msg_buffer,"Trace Exception at file: %s ,Line : %d , Function %s \n",__FILE__,__LINE__,__FUNCTION__);\
PrintErrorMsg(error_msg_buffer );\
delete[] error_msg_buffer;}
#else
#define TRACE
But I want to do it without using sprintf , just only by stringing and token pasting.
Any idea?
#endif
--Thanks in advance--
When you try to stringize something with #x, that x must be a macro parameter:
#define FOO #__LINE__ /* this is not okay */
#define BAR(x) #x /* this is okay */
But you cannot simply say BAR(__LINE__), because this will pass the token __LINE__ into BAR, where it is immediately turned into a string without expansion (this is by design), giving "__LINE__". The same thing happens with the token-pasting operator ##: expansion of their operands never happens.
The solution is to add indirection. You should always have these in your codebase somewhere:
#define STRINGIZE(x) STRINGIZE_SIMPLE(x)
#define STRINGIZE_SIMPLE(x) #x
#define CONCAT(first, second) CONCAT_SIMPLE(first, second)
#define CONCAT_SIMPLE(first, second) first ## second
Now STRINGIZE(__LINE__) turns to STRINGIZE_SIMPLE(__LINE__) which gets fully expanded to (for example) #123, which results in "123". Phew! I leave STRINGIZE_SIMPLE around on the off chance I want the original behavior. So your code would be something like:
#include <iostream>
#define STRINGIZE(x) STRINGIZE_SIMPLE(x)
#define STRINGIZE_SIMPLE(x) #x
#define TRACE() \
PrintErrorMsg("Trace exception in " __FILE__ \
" at line number " STRINGIZE(__LINE__) \
" in function " __FUNCTION__ ".")
void PrintErrorMsg(const char* str)
{
std::cout << str << std::endl;
}
int main()
{
TRACE();
}
You need this kind of silliness, unfortunately.
#include <stdio.h>
#define TRACE2(f,l) printf("I am at file: " f " and line: " #l "\n")
#define TRACE1(f,l) TRACE2(f,l)
#define TRACE() TRACE1(__FILE__, __LINE__)
int main(void)
{
TRACE();
TRACE();
}
I am at file: test.cpp and line: 9
I am at file: test.cpp and line: 10
This is my assert function (it wont compile "error C2110: '+' : cannot add two pointers"):
#define CHAR(x) #x
template<typename T>
inline void ASSERT(T x)
{
if(!x)
{
std::string s("ERROR! Assert " + CHAR(x) + " failed. In file " + __FILE__ +
" at line " + __LINE__ + ".");
std::wstring temp(s.length(), L' ');
std::copy(s.begin(), s.end(), temp.begin());
getLogger().Write(temp);
}
}
Any idea of how to fix it?
String Literals are easily reduced to char pointers, which cannot be added as you try to do with "ERROR! Assert " + CHAR(x) + " failed. In file ".... However, C++ has the handy feature of doing this automatically before compilation! (the preprocessor does this). Even better, it has a handy tool for making wide strings at compile time. So, you want:
#define _T(x) L ## x
#define CHAR(x) #x
#define CHAR2(x) CHAR(x)
#define ASSERT(x) ASSERT2(x, CHAR(x), __FILE__, CHAR2(__LINE__))
#define ASSERT2(x, t, f, l) \
if(!x) \
getLogger().Write(L"ERROR! Assert " _T(t) L" failed. In file " _T(f) L" at line " _T(l) L".");
http://ideone.com/0ibcj
The compiler error is quite clear; you are trying to apply the + operator to string literals. A quick way to fix it is enclosing the first string literal in std::string().
As #James McNellis pointed out, note that FILE and LINE will point to the file and line of the assert function declaration.
You cannot use the + operator to concatenate two char*s; you need printf or some sort of thing for that.
"ERROR! Assert " is a null-terminated, C-style string. You can't execute operator+ on it.
A few issues:
Generally an assert should break into the debugger or dump if one is not attached. This will not.
As already mentioned, your LINE and FILE require use in a macro
You need a couple "helper" macros to get the strings working properly
Try something along these lines:
#define ASSERT_QUOTE_(x) #x
#define ASSERT_QUOTE_(x) ASSERT_QUOTE_(x)
#define MY_ASSERT(cond) \
if(cond) {} else { \
std::stringstream ss; \
ss << "ERROR! Assert " << ASSERT_QUOTE(cond) << " failed. In file " << __FILE__ << " at line " << __LINE__ << "."; \
getLogger().Write(ss.str()); \
}
Be careful trying to use STL here however. I suggest you have your logger's Write() function take variable arguments and process them with printf() or perhaps boost::format