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
CODE PROJECT For Those Who Code
  • Home
  • Articles
  • FAQ
Community
  1. Home
  2. General Programming
  3. C / C++ / MFC
  4. Passing a class to a sprintf() and similar

Passing a class to a sprintf() and similar

Scheduled Pinned Locked Moved C / C++ / MFC
questionc++
18 Posts 6 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.
  • C Offline
    C Offline
    Crazy Joe Devola
    wrote on last edited by
    #1

    I am trying to pass a class I wrote to sprintf(). Not the class itself actually, but a pointer to a string the class holds. With the VC++ CString class it works fine: sprintf(t, "%s", cst); But with my class, it either crashes the program or puts garbage into the t buffer: sprintf(t, "%s", c); Unless I use casting, and then it works ok: sprintf(t, "%s", (char *)c); What is my class missing? Some kind of an operator? Here is my code:

    class C1
    {
    public:
    C1()
    {
    sprintf(m_Data,"C1 class");
    }

    operator char *() { return m_Data; }

    private:
    char m_Data[100];
    };

    int main(int argc, char* argv[])
    {
    char t[1000]="";
    C1 c;
    CString cst("Test c string");

    sprintf(t, "%s", cst);
    sprintf(t, "%s", c);
    return 0;
    }

    CPalliniC L 2 Replies Last reply
    0
    • C Crazy Joe Devola

      I am trying to pass a class I wrote to sprintf(). Not the class itself actually, but a pointer to a string the class holds. With the VC++ CString class it works fine: sprintf(t, "%s", cst); But with my class, it either crashes the program or puts garbage into the t buffer: sprintf(t, "%s", c); Unless I use casting, and then it works ok: sprintf(t, "%s", (char *)c); What is my class missing? Some kind of an operator? Here is my code:

      class C1
      {
      public:
      C1()
      {
      sprintf(m_Data,"C1 class");
      }

      operator char *() { return m_Data; }

      private:
      char m_Data[100];
      };

      int main(int argc, char* argv[])
      {
      char t[1000]="";
      C1 c;
      CString cst("Test c string");

      sprintf(t, "%s", cst);
      sprintf(t, "%s", c);
      return 0;
      }

      CPalliniC Offline
      CPalliniC Offline
      CPallini
      wrote on last edited by
      #2

      Crazy Joe Devola wrote:

      What is my class missing? Some kind of an operator?

      You are missing nothing: Try the following statement:

      char * p = c;

      However the cast (either the one you used or the static_cast<char *>()) is required in sprintf due to its signature (the type of its variadic arguments is established dynamically based on the fmt parameter) the char*() operator must be explicitely called.

      THESE PEOPLE REALLY BOTHER ME!! How can they know what you should do without knowing what you want done?!?! -- C++ FQA Lite

      In testa che avete, signor di Ceprano?

      C 1 Reply Last reply
      0
      • CPalliniC CPallini

        Crazy Joe Devola wrote:

        What is my class missing? Some kind of an operator?

        You are missing nothing: Try the following statement:

        char * p = c;

        However the cast (either the one you used or the static_cast<char *>()) is required in sprintf due to its signature (the type of its variadic arguments is established dynamically based on the fmt parameter) the char*() operator must be explicitely called.

        THESE PEOPLE REALLY BOTHER ME!! How can they know what you should do without knowing what you want done?!?! -- C++ FQA Lite

        C Offline
        C Offline
        Crazy Joe Devola
        wrote on last edited by
        #3

        Thank you. Yes, char * works. However, when i use the CString class as in my example, no casting or conversion is required at all. What does the CString class have that my C1 does not? (obviously a lot :-) but specifically for what I am trying to do...)

        CPalliniC 1 Reply Last reply
        0
        • C Crazy Joe Devola

          Thank you. Yes, char * works. However, when i use the CString class as in my example, no casting or conversion is required at all. What does the CString class have that my C1 does not? (obviously a lot :-) but specifically for what I am trying to do...)

          CPalliniC Offline
          CPalliniC Offline
          CPallini
          wrote on last edited by
          #4

          You are right, of course. And that is, at the moment, a mystery to me too. :-) However, have a look at this MSDN page: CString::operator LPCTSTR[^]. That's make me guess in your actual code m_Data is not the unique (and not the first) data member.

          THESE PEOPLE REALLY BOTHER ME!! How can they know what you should do without knowing what you want done?!?! -- C++ FQA Lite

          In testa che avete, signor di Ceprano?

          L B 2 Replies Last reply
          0
          • CPalliniC CPallini

            You are right, of course. And that is, at the moment, a mystery to me too. :-) However, have a look at this MSDN page: CString::operator LPCTSTR[^]. That's make me guess in your actual code m_Data is not the unique (and not the first) data member.

            THESE PEOPLE REALLY BOTHER ME!! How can they know what you should do without knowing what you want done?!?! -- C++ FQA Lite

            L Offline
            L Offline
            Lost User
            wrote on last edited by
            #5

            I just tested OP's code (without the CString - no MFC or ATL) and it sends the actual C1 object as the last parameter, so the pointer will be rubbish. I also would like to know how CString manages to coerce the () operator without a cast.

            CPalliniC 1 Reply Last reply
            0
            • L Lost User

              I just tested OP's code (without the CString - no MFC or ATL) and it sends the actual C1 object as the last parameter, so the pointer will be rubbish. I also would like to know how CString manages to coerce the () operator without a cast.

              CPalliniC Offline
              CPalliniC Offline
              CPallini
              wrote on last edited by
              #6

              It is not rubbish, in my test (VS2012). It is pointer to the C1 object, having the same address of its first data member (m_Data) in this simple case, so everything goes right (of course if you insert, before m_Data, another member variable, for instance an int, the sprintf gets some garbage). In the linked MSDN page they indded suggest to explicitely cast the CString object when used as sprintf parameter.

              THESE PEOPLE REALLY BOTHER ME!! How can they know what you should do without knowing what you want done?!?! -- C++ FQA Lite

              In testa che avete, signor di Ceprano?

              L 2 Replies Last reply
              0
              • CPalliniC CPallini

                It is not rubbish, in my test (VS2012). It is pointer to the C1 object, having the same address of its first data member (m_Data) in this simple case, so everything goes right (of course if you insert, before m_Data, another member variable, for instance an int, the sprintf gets some garbage). In the linked MSDN page they indded suggest to explicitely cast the CString object when used as sprintf parameter.

                THESE PEOPLE REALLY BOTHER ME!! How can they know what you should do without knowing what you want done?!?! -- C++ FQA Lite

                L Offline
                L Offline
                Lost User
                wrote on last edited by
                #7

                Interesting. I used VS2010 Express, and copying OP's code, it copies the entire object onto the stack, thus the 'pointer' is garbage. When I use a cast it pushes the address of the object onto the stack and works as it should. More testing required ...

                1 Reply Last reply
                0
                • C Crazy Joe Devola

                  I am trying to pass a class I wrote to sprintf(). Not the class itself actually, but a pointer to a string the class holds. With the VC++ CString class it works fine: sprintf(t, "%s", cst); But with my class, it either crashes the program or puts garbage into the t buffer: sprintf(t, "%s", c); Unless I use casting, and then it works ok: sprintf(t, "%s", (char *)c); What is my class missing? Some kind of an operator? Here is my code:

                  class C1
                  {
                  public:
                  C1()
                  {
                  sprintf(m_Data,"C1 class");
                  }

                  operator char *() { return m_Data; }

                  private:
                  char m_Data[100];
                  };

                  int main(int argc, char* argv[])
                  {
                  char t[1000]="";
                  C1 c;
                  CString cst("Test c string");

                  sprintf(t, "%s", cst);
                  sprintf(t, "%s", c);
                  return 0;
                  }

                  L Offline
                  L Offline
                  Lost User
                  wrote on last edited by
                  #8

                  OK, I finally figured it out. CString is a bit more of a sophisticated class, and will not use a fixed length buffer for its data. It uses a dynamically allocated one, and as long as that is the first data item in the class definition, the sprintf call will work; although it is luck rather than anything else. You can check this out with the following code:

                  class C1
                  {
                  public:
                  C1()
                  {
                  // allocate space for the text and then copy to the dynamic buffer
                  m_Data = (char*)malloc(100);
                  sprintf(m_Data,"C1 class");
                  }

                  operator char \*() { return m\_Data; }
                  

                  private:
                  char* m_Data; // make buffer a pointer

                  };
                  

                  When you now use the object without the cast, it just copies the object's data onto the stack, and since this data is a pointer to the actual text it all works as you expect. But be aware that this may have unintended consequences, so always use the cast when you want this behaviour.

                  CPalliniC J A C 4 Replies Last reply
                  0
                  • CPalliniC CPallini

                    It is not rubbish, in my test (VS2012). It is pointer to the C1 object, having the same address of its first data member (m_Data) in this simple case, so everything goes right (of course if you insert, before m_Data, another member variable, for instance an int, the sprintf gets some garbage). In the linked MSDN page they indded suggest to explicitely cast the CString object when used as sprintf parameter.

                    THESE PEOPLE REALLY BOTHER ME!! How can they know what you should do without knowing what you want done?!?! -- C++ FQA Lite

                    L Offline
                    L Offline
                    Lost User
                    wrote on last edited by
                    #9

                    See my answer to OP below.

                    1 Reply Last reply
                    0
                    • L Lost User

                      OK, I finally figured it out. CString is a bit more of a sophisticated class, and will not use a fixed length buffer for its data. It uses a dynamically allocated one, and as long as that is the first data item in the class definition, the sprintf call will work; although it is luck rather than anything else. You can check this out with the following code:

                      class C1
                      {
                      public:
                      C1()
                      {
                      // allocate space for the text and then copy to the dynamic buffer
                      m_Data = (char*)malloc(100);
                      sprintf(m_Data,"C1 class");
                      }

                      operator char \*() { return m\_Data; }
                      

                      private:
                      char* m_Data; // make buffer a pointer

                      };
                      

                      When you now use the object without the cast, it just copies the object's data onto the stack, and since this data is a pointer to the actual text it all works as you expect. But be aware that this may have unintended consequences, so always use the cast when you want this behaviour.

                      CPalliniC Offline
                      CPalliniC Offline
                      CPallini
                      wrote on last edited by
                      #10

                      However, I don't see the difference on my system (that is it works with m_Data as provided in the OP).

                      THESE PEOPLE REALLY BOTHER ME!! How can they know what you should do without knowing what you want done?!?! -- C++ FQA Lite

                      In testa che avete, signor di Ceprano?

                      L 1 Reply Last reply
                      0
                      • CPalliniC CPallini

                        However, I don't see the difference on my system (that is it works with m_Data as provided in the OP).

                        THESE PEOPLE REALLY BOTHER ME!! How can they know what you should do without knowing what you want done?!?! -- C++ FQA Lite

                        L Offline
                        L Offline
                        Lost User
                        wrote on last edited by
                        #11

                        Definitely different for me, it only worked with the modified code.

                        CPalliniC 1 Reply Last reply
                        0
                        • L Lost User

                          Definitely different for me, it only worked with the modified code.

                          CPalliniC Offline
                          CPalliniC Offline
                          CPallini
                          wrote on last edited by
                          #12

                          And apparently the 'strange case' is mine.

                          THESE PEOPLE REALLY BOTHER ME!! How can they know what you should do without knowing what you want done?!?! -- C++ FQA Lite

                          In testa che avete, signor di Ceprano?

                          L 1 Reply Last reply
                          0
                          • CPalliniC CPallini

                            And apparently the 'strange case' is mine.

                            THESE PEOPLE REALLY BOTHER ME!! How can they know what you should do without knowing what you want done?!?! -- C++ FQA Lite

                            L Offline
                            L Offline
                            Lost User
                            wrote on last edited by
                            #13

                            Well it can't be just you, there must be something else that is not obvious that happens in your compiler. I only managed to work out what was happening on my system by getting the assembler listing from the compiler, so maybe your version of the compiler is different from the two I used.

                            1 Reply Last reply
                            0
                            • L Lost User

                              OK, I finally figured it out. CString is a bit more of a sophisticated class, and will not use a fixed length buffer for its data. It uses a dynamically allocated one, and as long as that is the first data item in the class definition, the sprintf call will work; although it is luck rather than anything else. You can check this out with the following code:

                              class C1
                              {
                              public:
                              C1()
                              {
                              // allocate space for the text and then copy to the dynamic buffer
                              m_Data = (char*)malloc(100);
                              sprintf(m_Data,"C1 class");
                              }

                              operator char \*() { return m\_Data; }
                              

                              private:
                              char* m_Data; // make buffer a pointer

                              };
                              

                              When you now use the object without the cast, it just copies the object's data onto the stack, and since this data is a pointer to the actual text it all works as you expect. But be aware that this may have unintended consequences, so always use the cast when you want this behaviour.

                              J Offline
                              J Offline
                              jschell
                              wrote on last edited by
                              #14

                              Richard MacCutchan wrote:

                              although it is luck rather than anything else

                              The class has been that way for a very long time because I remember being mystified by exactly the same thing a long, long time ago. I think when I looked at source for the class it was also set up in such a way that there was in fact basically one data member (there was some tricky code going on.) So even if you used it in the middle everything still works. Because of that I wonder if there has been a deliberate effort to insure that behavior (versus luck.)

                              1 Reply Last reply
                              0
                              • L Lost User

                                OK, I finally figured it out. CString is a bit more of a sophisticated class, and will not use a fixed length buffer for its data. It uses a dynamically allocated one, and as long as that is the first data item in the class definition, the sprintf call will work; although it is luck rather than anything else. You can check this out with the following code:

                                class C1
                                {
                                public:
                                C1()
                                {
                                // allocate space for the text and then copy to the dynamic buffer
                                m_Data = (char*)malloc(100);
                                sprintf(m_Data,"C1 class");
                                }

                                operator char \*() { return m\_Data; }
                                

                                private:
                                char* m_Data; // make buffer a pointer

                                };
                                

                                When you now use the object without the cast, it just copies the object's data onto the stack, and since this data is a pointer to the actual text it all works as you expect. But be aware that this may have unintended consequences, so always use the cast when you want this behaviour.

                                A Offline
                                A Offline
                                Albert Holguin
                                wrote on last edited by
                                #15

                                I thought this was done on pupose on CString for this very reason... (not sure if you mean the luck part referring to CString)

                                J 1 Reply Last reply
                                0
                                • L Lost User

                                  OK, I finally figured it out. CString is a bit more of a sophisticated class, and will not use a fixed length buffer for its data. It uses a dynamically allocated one, and as long as that is the first data item in the class definition, the sprintf call will work; although it is luck rather than anything else. You can check this out with the following code:

                                  class C1
                                  {
                                  public:
                                  C1()
                                  {
                                  // allocate space for the text and then copy to the dynamic buffer
                                  m_Data = (char*)malloc(100);
                                  sprintf(m_Data,"C1 class");
                                  }

                                  operator char \*() { return m\_Data; }
                                  

                                  private:
                                  char* m_Data; // make buffer a pointer

                                  };
                                  

                                  When you now use the object without the cast, it just copies the object's data onto the stack, and since this data is a pointer to the actual text it all works as you expect. But be aware that this may have unintended consequences, so always use the cast when you want this behaviour.

                                  C Offline
                                  C Offline
                                  Crazy Joe Devola
                                  wrote on last edited by
                                  #16

                                  Cool! thank you very much Richard. :thumbsup:

                                  1 Reply Last reply
                                  0
                                  • CPalliniC CPallini

                                    You are right, of course. And that is, at the moment, a mystery to me too. :-) However, have a look at this MSDN page: CString::operator LPCTSTR[^]. That's make me guess in your actual code m_Data is not the unique (and not the first) data member.

                                    THESE PEOPLE REALLY BOTHER ME!! How can they know what you should do without knowing what you want done?!?! -- C++ FQA Lite

                                    B Offline
                                    B Offline
                                    Bram van Kampen
                                    wrote on last edited by
                                    #17

                                    Well I have noticed, VC 2012 has different parsing and scanning rules than earlier versions. The question is: Did the rules change in the standard, or was it incorrectly implemented by Microsoft. :)

                                    Bram van Kampen

                                    1 Reply Last reply
                                    0
                                    • A Albert Holguin

                                      I thought this was done on pupose on CString for this very reason... (not sure if you mean the luck part referring to CString)

                                      J Offline
                                      J Offline
                                      jschell
                                      wrote on last edited by
                                      #18

                                      Albert Holguin wrote:

                                      I thought this was done on pupose on CString for this very reason... (not sure if you mean the luck part referring to CString)

                                      Yes that is what I meant - I was supposing that it was possible that it was planned that way from the start.

                                      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