Passing a class to a sprintf() and similar
-
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...)
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
-
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
-
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 howCString
manages to coerce the()
operator without a cast.It is not rubbish, in my test (
VS2012
). It is pointer to theC1
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, beforem_Data
, another member variable, for instance anint
, thesprintf
gets some garbage). In the linkedMSDN
page they indded suggest to explicitely cast theCString
object when used assprintf
parameter.THESE PEOPLE REALLY BOTHER ME!! How can they know what you should do without knowing what you want done?!?! -- C++ FQA Lite
-
It is not rubbish, in my test (
VS2012
). It is pointer to theC1
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, beforem_Data
, another member variable, for instance anint
, thesprintf
gets some garbage). In the linkedMSDN
page they indded suggest to explicitely cast theCString
object when used assprintf
parameter.THESE PEOPLE REALLY BOTHER ME!! How can they know what you should do without knowing what you want done?!?! -- C++ FQA Lite
-
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;
}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, thesprintf
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.
-
It is not rubbish, in my test (
VS2012
). It is pointer to theC1
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, beforem_Data
, another member variable, for instance anint
, thesprintf
gets some garbage). In the linkedMSDN
page they indded suggest to explicitely cast theCString
object when used assprintf
parameter.THESE PEOPLE REALLY BOTHER ME!! How can they know what you should do without knowing what you want done?!?! -- C++ FQA Lite
-
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, thesprintf
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.
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
-
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
-
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
-
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
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.
-
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, thesprintf
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.
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.)
-
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, thesprintf
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.
I thought this was done on pupose on CString for this very reason... (not sure if you mean the luck part referring to CString)
-
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, thesprintf
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.
Cool! thank you very much Richard. :thumbsup:
-
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
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
-
I thought this was done on pupose on CString for this very reason... (not sure if you mean the luck part referring to CString)
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.