Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C / C++ / MFC
  4. CString as variable arguments

CString as variable arguments

Scheduled Pinned Locked Moved C / C++ / MFC
question
5 Posts 3 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • R Offline
    R Offline
    Royce Fickling 0
    wrote on last edited by
    #1

    I have a function that uses a variable argument list, but the va_arg macro always throws an exception. Why can't I use CString objects as my arguments? What am I doing wrong? My code is below.

    void COdb::WriteAttribute( CStdioFile& fileOutput,
    const CString& strTagName,
    const CString& strAttribute,
    const CString& strValue, ... )
    {
    va_list vl;
    va_start( vl, strValue );

    CString strBuffer;
    strBuffer.Format( "  <%s %s=\\"%s\\"/>", 
    			strTagName, strAttribute, strValue );
    
    CString strOpAttr = va\_arg( vl, CString );
    

    }

    D M 2 Replies Last reply
    0
    • R Royce Fickling 0

      I have a function that uses a variable argument list, but the va_arg macro always throws an exception. Why can't I use CString objects as my arguments? What am I doing wrong? My code is below.

      void COdb::WriteAttribute( CStdioFile& fileOutput,
      const CString& strTagName,
      const CString& strAttribute,
      const CString& strValue, ... )
      {
      va_list vl;
      va_start( vl, strValue );

      CString strBuffer;
      strBuffer.Format( "  <%s %s=\\"%s\\"/>", 
      			strTagName, strAttribute, strValue );
      
      CString strOpAttr = va\_arg( vl, CString );
      

      }

      D Offline
      D Offline
      David Crow
      wrote on last edited by
      #2

      Royce Fickling wrote:

      Why can't I use CString objects as my arguments?

      Why don't you use LPCTSTR as the parameter types instead?

      void COdb::WriteAttribute( CStdioFile& fileOutput, LPCTSTR strTagName, LPCTSTR strAttribute, LPCTSTR strValue, ... )
      {
      va_list vl;
      va_start( vl, strValue );
      CString strBuffer;
      strBuffer.Format( " <%s %s=\"%s\"/>", strTagName, strAttribute, strValue);
      LPCTSTR strOpAttr = va_arg( vl, LPCTSTR);
      }

      "Love people and use things, not love things and use people." - Unknown

      "The brick walls are there for a reason...to stop the people who don't want it badly enough." - Randy Pausch

      1 Reply Last reply
      0
      • R Royce Fickling 0

        I have a function that uses a variable argument list, but the va_arg macro always throws an exception. Why can't I use CString objects as my arguments? What am I doing wrong? My code is below.

        void COdb::WriteAttribute( CStdioFile& fileOutput,
        const CString& strTagName,
        const CString& strAttribute,
        const CString& strValue, ... )
        {
        va_list vl;
        va_start( vl, strValue );

        CString strBuffer;
        strBuffer.Format( "  <%s %s=\\"%s\\"/>", 
        			strTagName, strAttribute, strValue );
        
        CString strOpAttr = va\_arg( vl, CString );
        

        }

        M Offline
        M Offline
        Mark Salsbery
        wrote on last edited by
        #3

        Interesting. I looked at this for a while. The problem is the "strValue" argument. The offset of the strValue parameter is used to calculate the offset of the start of the variable-length parameter list. If you don't pass it by reference the function works fine. I can't figure out why the reference doesn't work - the sizeof a reference is the same as the sizeof a CString (4 bytes on my 32-bit build), so I would expect the same result. I guess references are passed on the stack differently. I don't think this old C feature was meant to deal with C++ references anyway... Regardless, passing strValue by value instead of by reference fixes it:

        void COdb::WriteAttribute( CStdioFile& fileOutput,
        const CString& strTagName,
        const CString& strAttribute,
        const CString strValue, ... )
        ...

        If anyone wants to analyze this further, here's the macro definitions:

        #define _ADDRESSOF(v) ( &reinterpret_cast<const char &>(v) )
        #define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )

        #define _crt_va_start(ap,v) ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )
        #define _crt_va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
        #define _crt_va_end(ap) ( ap = (va_list)0 )

        *edit* Now that the caffeine has kicked in, I realize taking the address of a reference gives you the address of the object referenced, not the address of the reference. Yeah - those macros weren't meant to work with references :) Mark

        Mark Salsbery Microsoft MVP - Visual C++ :java:

        modified on Friday, August 29, 2008 2:09 PM

        R 1 Reply Last reply
        0
        • M Mark Salsbery

          Interesting. I looked at this for a while. The problem is the "strValue" argument. The offset of the strValue parameter is used to calculate the offset of the start of the variable-length parameter list. If you don't pass it by reference the function works fine. I can't figure out why the reference doesn't work - the sizeof a reference is the same as the sizeof a CString (4 bytes on my 32-bit build), so I would expect the same result. I guess references are passed on the stack differently. I don't think this old C feature was meant to deal with C++ references anyway... Regardless, passing strValue by value instead of by reference fixes it:

          void COdb::WriteAttribute( CStdioFile& fileOutput,
          const CString& strTagName,
          const CString& strAttribute,
          const CString strValue, ... )
          ...

          If anyone wants to analyze this further, here's the macro definitions:

          #define _ADDRESSOF(v) ( &reinterpret_cast<const char &>(v) )
          #define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )

          #define _crt_va_start(ap,v) ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )
          #define _crt_va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
          #define _crt_va_end(ap) ( ap = (va_list)0 )

          *edit* Now that the caffeine has kicked in, I realize taking the address of a reference gives you the address of the object referenced, not the address of the reference. Yeah - those macros weren't meant to work with references :) Mark

          Mark Salsbery Microsoft MVP - Visual C++ :java:

          modified on Friday, August 29, 2008 2:09 PM

          R Offline
          R Offline
          Royce Fickling 0
          wrote on last edited by
          #4

          After converting the CString reference parameters to LPCTSTR parameters, it works, but only when the optional parameters are actually passed. When they are not passed, I still get garbage in the 1st optional parameter. So how do I determine when I have them and when I don't? I thought that if the optional arguments were not passed, the first call to va_arg would return a null, but that is not the case. I have posted my code below.

          void COdb::WriteAttribute( CStdioFile& fileOutput,
          LPCTSTR strTagName,
          LPCTSTR strAttribute,
          LPCTSTR strValue, ... )
          {
          va_list vl;
          va_start( vl, strValue );

          CString strBuffer;
          strBuffer.Format( "  <%s %s=\\"%s\\"/>", 
          			strTagName, strAttribute, strValue );
          
          LPCTSTR pstrOpArg = va\_arg( vl, LPCTSTR );
          CString strOption;
          bool bAttr = true;
          while ( pstrOpArg )
          {
          	if ( bAttr )
          	{
          		strOption.Format( "%s=", pstrOpArg );
          		strBuffer += strOption;
          		bAttr = false;
          	}
          	else
          	{
          		strOption.Format( "\\"%s\\"", pstrOpArg );
          		strBuffer += strOption;
          		bAttr = true;
          	}
          
          	pstrOpArg = va\_arg( vl, LPCTSTR );
          }
          
          fileOutput.WriteString( strBuffer );
          

          }

          M 1 Reply Last reply
          0
          • R Royce Fickling 0

            After converting the CString reference parameters to LPCTSTR parameters, it works, but only when the optional parameters are actually passed. When they are not passed, I still get garbage in the 1st optional parameter. So how do I determine when I have them and when I don't? I thought that if the optional arguments were not passed, the first call to va_arg would return a null, but that is not the case. I have posted my code below.

            void COdb::WriteAttribute( CStdioFile& fileOutput,
            LPCTSTR strTagName,
            LPCTSTR strAttribute,
            LPCTSTR strValue, ... )
            {
            va_list vl;
            va_start( vl, strValue );

            CString strBuffer;
            strBuffer.Format( "  <%s %s=\\"%s\\"/>", 
            			strTagName, strAttribute, strValue );
            
            LPCTSTR pstrOpArg = va\_arg( vl, LPCTSTR );
            CString strOption;
            bool bAttr = true;
            while ( pstrOpArg )
            {
            	if ( bAttr )
            	{
            		strOption.Format( "%s=", pstrOpArg );
            		strBuffer += strOption;
            		bAttr = false;
            	}
            	else
            	{
            		strOption.Format( "\\"%s\\"", pstrOpArg );
            		strBuffer += strOption;
            		bAttr = true;
            	}
            
            	pstrOpArg = va\_arg( vl, LPCTSTR );
            }
            
            fileOutput.WriteString( strBuffer );
            

            }

            M Offline
            M Offline
            Mark Salsbery
            wrote on last edited by
            #5

            Royce Fickling wrote:

            I thought that if the optional arguments were not passed, the first call to va_arg would return a null, but that is not the case.

            Yes, that is NOT the case. You'd need to pass a NULL parameter.

            Mark Salsbery Microsoft MVP - Visual C++ :java:

            1 Reply Last reply
            0
            Reply
            • Reply as topic
            Log in to reply
            • Oldest to Newest
            • Newest to Oldest
            • Most Votes


            • Login

            • Don't have an account? Register

            • Login or register to search.
            • First post
              Last post
            0
            • Categories
            • Recent
            • Tags
            • Popular
            • World
            • Users
            • Groups