CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 11 of 11
  1. #1
    Join Date
    May 2002
    Posts
    1,435

    __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__)

  2. #2
    Join Date
    Oct 1999
    Location
    Germany
    Posts
    238
    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.

  3. #3
    Join Date
    Aug 2002
    Location
    Madrid
    Posts
    4,588
    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.

  4. #4
    Join Date
    Oct 1999
    Location
    Germany
    Posts
    238
    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.

  5. #5
    Join Date
    Aug 2002
    Location
    Madrid
    Posts
    4,588
    Yes I see it works, but why does it work ?

  6. #6
    Join Date
    May 2001
    Posts
    69
    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.

  7. #7
    Join Date
    Oct 1999
    Location
    Germany
    Posts
    238
    beats me, bro.

  8. #8
    Join Date
    May 2002
    Posts
    1,435
    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.

  9. #9
    Join Date
    Aug 2001
    Location
    Minnesota, USA
    Posts
    801
    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

  10. #10
    Join Date
    Jun 2001
    Location
    Switzerland
    Posts
    4,443
    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.
    Gabriel, CodeGuru moderator

    Forever trusting who we are
    And nothing else matters
    - Metallica

    Learn about the advantages of std::vector.

  11. #11
    Join Date
    Aug 2001
    Location
    Minnesota, USA
    Posts
    801
    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
  •  





Click Here to Expand Forum to Full Width

Featured