-
October 22nd, 2002, 12:34 PM
#1
__LINE__ MACRO to string literal
Does anyone know how to change the predefined __LINE__ MACRO to a string literal in the context of the pre-processor?
I want to print the current line number by means of #pragma message.
This prints string literal "999":
#pragma message("999")
This is what I want to do:
#pragma message(__LINE__)
-
October 22nd, 2002, 01:57 PM
#2
Hi !
Try the following:
#define h2(l) #l
#define h1(l) h2(l)
#define msg(s) message ( #s " " h1( __LINE__ ) )
#pragma msg( This is line )
Let me know if this helped you.
-
October 22nd, 2002, 02:01 PM
#3
This is very interesting.
Why is it that you need both h1 and h2 ?
It seems that if you nest macros, the nested one is always called with a string literal argument, but why ?
Last edited by Yves M; October 22nd, 2002 at 02:03 PM.
-
October 22nd, 2002, 02:11 PM
#4
As to what I figured out it this needs to be done for __LINE__ to actually expand
to the current linenumber.
I don't remember where I found this, but its quite useful to mark unfinished code.
Gives you a nice message during compilation.
-
October 22nd, 2002, 02:13 PM
#5
Yes I see it works, but why does it work ?
-
October 22nd, 2002, 02:31 PM
#6
This exactly why I spent quite a bit of time on this long time ago:: marking unfinished/questionable code to comeback to later. Very usefull b/c one can see it during compilation.
What I have, is a small toolbar with 3 buttons for quickly marking the code as "Obsolete", and "TODO".
Right now both simply insert the following at the current cursor line position:
#pragma message ("Obsolete code." __FILE__) //
-and-
#pragma message ("TO DO:." __FILE__)
I wanted it to insert line numbers as well, but could never get it to do this.
Now I'm going to complicate the problem slightly (and possibly make it unsolvable)
Those macros are ready to be inserted into any file, so I don't want those to depend on anything already being in the file (like already defined macros)
Is it possible to do the whole thing in one line, so that it can be part of that line, and thus easily insertable by just clcking on a toolbar?
I'm thinking that MS's assert() function does it somehow (or even more). Have you noticed that whatever expression that you pass to it, it can display it in its assertion dialog??? How does it do that????????? If we can figure out this, we can figure out anything
(Hey Yves M - we meet again )
Lenny
Originally posted by mdangers
As to what I figured out it this needs to be done for __LINE__ to actually expand
to the current linenumber.
I don't remember where I found this, but its quite useful to mark unfinished code.
Gives you a nice message during compilation.
-
October 22nd, 2002, 02:41 PM
#7
-
October 22nd, 2002, 03:12 PM
#8
Thanks, that's exactly what I wanted.
And also the reason - I want to mark code that needs to be looked at later and I want to format the message in the output window so I can simply double-click on it to go directly to the source code file and line number.
I had little hope that this would be possible - I'm really amazed.
-
October 22nd, 2002, 04:53 PM
#9
Replying to LBensman:
You won't be able to do the multiple preprocessor statements on one line. The compiler docs state that you can't do this. However, you could just put the definitions in one of your common header files, and then you could use the #pragma anywhere that header is included.
If you want a pretty easy way to double click and get to the error as well (like dev studio does with regular errors/warnings), you just have to format the string properly. Here's one which does it:
Code:
#define h2(l) #l
#define h1(l) h2(l)
#define msg(s) message ( __FILE__"(" h1( __LINE__ ) ") : " s )
#pragma msg( "Don't forget to fix me" )
Note that this version requries that the #pragma msg( "xx" ) takes a string. I think that makes it easier to read in the code.
Onto the _ASSERTE question. The _ASSERTE macro is defined like this in crtdbg.h:
Code:
#define _ASSERTE(expr) \
do { if (!(expr) && \
(1 == _CrtDbgReport(_CRT_ASSERT, __FILE__, __LINE__, NULL, #expr))) \
_CrtDbgBreak(); } while (0)
That #expr that you see there tells the preprocessor to take expr and wrap it in quotes before the compiler will see it. It's a pretty neat way to get a string value from a #defined name (or an enum), so we could say:
Code:
enum Errors
{
BadError,
ReallyBadError,
UhOhProgramIsNotHappy,
// More errors would be here maybe.
};
void Error( Errors error )
{
// Crack the error
TCHAR * a_pszError = _T("");
#define ERROR_CASE(Enum) case Enum: a_pszError = _T(#Enum); break;
switch( error )
{
ERROR_CASE( BadError )
ERROR_CASE( ReallyBadError )
ERROR_CASE( UhOhProgramIsNotHappy )
// More cases would be here if there were more errors.
}
_tprintf( _T("An internal error occurred: %s\n"), a_pszError );
}
It's pretty cool stuff, but a strange (and some will say not too good) use of the preprocessor I know.
Chris Richardson
-
October 23rd, 2002, 02:44 AM
#10
One small comment:
If you define a macro named 'msg' you are looking for trouble. Use something that is less common, like 'LINE_MESSAGE'
As for why it works, I think the explanation is that the preprocessor does multiple passes over the file until every known macro is expanded. The trick is to have the __LINE__ macro expanded in a way that makes it a parameter for another macro. You define h1(l) as being h2(l) just to enforce another preprocessor pass *after* __LINE__ was expanded.
When the preprocessor encounters this line:
Code:
#pragma msg( "Don't forget to fix me" )
it will expand it to
Code:
#pragma message(__FILE__ "("h1( __LINE__ )" ) : Don't forget to fix me")
In a second step, it will look whether there is something else to expand, and will see __FILE__, __LINE__ and h1. Expanding them, will result in
Code:
#pragma message("C:\Yourfile.cpp(" h2(999) " " ) : Don't forget to fix me")
In the third pass, it will recognize h2 as a macro and will convert its parameter into a string literal.
Btw, thanks mdangers. I also was looking for this trick for a long time Here how I implemented it using your idea:
Code:
#define LINE_TO_LITERAL_2(l) #l
#define LINE_TO_LITERAL_1(l) LINE_TO_LITERAL_2(l)
#define LINE_MESSAGE(s) message ( __FILE__ "(" LINE_TO_LITERAL_1( __LINE__ ) ") : " #s)
This way you avoid conflicts with common identifier names like 'msg' and you also can click on the message to go to that line.
-
October 23rd, 2002, 10:33 AM
#11
Gabriel is correct. I didn't mean to suggest using such a common name as "msg" for the name of the macro, but rather assumed the reader would know to rename it something less common and more meaningful.
About the macro expansion, Gabriel is correct that the preprocessor probably does multiple passes, but not over the whole file. It probably just does whole passes over the macro text until all the sub-macros have been expanded.
Chris Richardson
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|