Pass CString to printf?

Showing 1-45 of 45 messages
Pass CString to printf? Hannes 9/25/08 12:54 AM
Hi,

Is it safe to pass a CString to printf without explicit (LPCTSTR) cast?

The following MSDN article suggests it is NOT safe:
http://msdn.microsoft.com/en-us/library/awkwbzyc(VS.71).aspx
"...it is essential that you use an explicit type cast when passing a
CString object to a function that takes a variable number of arguments.
...
CString kindOfFruit = "bananas";
int      howmany = 25;
printf( "You have %d %s\n", howmany, (LPCTSTR)kindOfFruit );"


On the other hand, various newsgroup posts claim that CString was designed
specifically in such a way that the (LPCTSTR) cast would not be needed with
printf.

We are a team of 40+ developers who are converting several large projects
from char* to CString, and avoiding (LPCTSTR) would save us a lot of time.

Can someone with insight please clarify what the software developing
community should do in this case?

Thanks,

        / Hannes.

Re: Pass CString to printf? Mikel 9/25/08 1:42 AM
Just in case, I would follow MSDN's recommendation. Using the cast
won't do any harm, except for losing some time (is writing code
properly a time loss?), and not using it might do it, so...
Re: Pass CString to printf? Giovanni Dicanio 9/25/08 5:54 AM

"Hannes" <hannes.news@newsgroup.nospam> ha scritto nel messaggio
news:77D19855-6CFF-4690-B1AA-B56AB861C4FB@microsoft.com...

> Is it safe to pass a CString to printf without explicit (LPCTSTR) cast?

CString is designed in a special way such that this works safely.

Since VC2003 CString is actually a template class, and is derived from
template class CSimpleStringT.
You can read the implementation of CSimpleStringT in <atlsimpstr.h> header.
CSimpleStringT has a private data member:

  PXSTR m_pszData;

There is no virtual method, so CSimpleStringT has no v-table pointers
(there's no "lpVtbl").

So, as for memory layout, the "address" of a CSimpleStringT instance could
be safely "reinterpreted" as LPCTSTR (pointing to m_pszData), and this is
why passing CString instances to printf() works without the explicit
static_cast< LPCTSTR >.

Note that Microsoft programmers who wrote CSimpleStringT were very clever,
and put the pointer to CStringData (which is an internal class that stores
information like reference counts to string, etc.) *before* the m_pszData
member of CSimpleStringT.

In fact, you can read that CSimpleStringT::GetData does an "unusual" (but
meaningful) cast like this:

 CStringData* GetData() const throw()
 {
     return( reinterpret_cast< CStringData* >( m_pszData )-1 );
 }

This "magic" (actually, clever behaviour) allows safe use of CString
instances (simply derived from CSimpleStringT, with no virtual methods) in
%s slots for printf().

However, in the future this "clever" behaviour and this "magic" may
disappear... so I think that the best investment in future robust code is to
do the explicit static_cast.

Giovanni

Re: Pass CString to printf? Jonathan Wood 9/25/08 11:29 AM
I looked into this at one time. While it works and is safe, I recall that it
is not as efficient. I believe the code generated will create a copy of the
CString object and then pass that. Because of the way the CString class is
designed, it is equal to the address of the string.

By using the cast or calling the GetBuffer() method, you may be producing
much more efficient code.

--
Jonathan Wood
SoftCircuits Programming
http://www.softcircuits.com

"Hannes" <hannes.news@newsgroup.nospam> wrote in message
news:77D19855-6CFF-4690-B1AA-B56AB861C4FB@microsoft.com...

Re: Pass CString to printf? Tom Serface 9/25/08 11:55 AM
That may be significant if you are doing the printf call in a tight loop
like updating status information.

I'd still be more likely to just use CString::Format or
CString::FormatMessage and skip printf altogether.  That is a pretty thin
layer on top of it all.

Tom

"Jonathan Wood" <jw...@softcircuits.com> wrote in message
news:u8PGJzzHJHA.4060@TK2MSFTNGP03.phx.gbl...


>I looked into this at one time. While it works and is safe, I recall that
>it is not as efficient. I believe the code generated will create a copy of
>the CString object and then pass that. Because of the way the CString class
>is designed, it is equal to the address of the string.
>
> By using the cast or calling the GetBuffer() method, you may be producing
> much more efficient code.
>
> --
> Jonathan Wood
> SoftCircuits Programming
> http://www.softcircuits.com
>

Re: Pass CString to printf? Mark Salsbery [MVP] 9/25/08 12:45 PM
"Hannes" <hannes.news@newsgroup.nospam> wrote in message
news:77D19855-6CFF-4690-B1AA-B56AB861C4FB@microsoft.com...
> Hi,
>
> Is it safe to pass a CString to printf without explicit (LPCTSTR) cast?


Yes, and that's how it should be passed - with NO cast.

Using the cast will hide a bug if you move the code to a Unicode build.


Really, if you're using a generic TCHAR character type string like CString,
then you should be using generic text function mappings.
You should VERY rarely need a string cast if you do..

Mark

--
Mark Salsbery
Microsoft MVP - Visual C++

 

Re: Pass CString to printf? Jonathan Wood 9/25/08 12:55 PM
Mark,

>> Is it safe to pass a CString to printf without explicit (LPCTSTR) cast?
>
> Yes, and that's how it should be passed - with NO cast.
>
> Using the cast will hide a bug if you move the code to a Unicode build.

I must confess that I'm pretty surprised someone would suggest in a thread
like this that the typecast can cause a bug, and yet not even hint at what
that bug might be.

I posted that the typecase can be more efficient, and then explained the
details of why.

Any chance you'll do the same and explain why we should use the less
efficient syntax?

--
Jonathan Wood
SoftCircuits Programming
http://www.softcircuits.com

Re: Pass CString to printf? Jonathan Wood 9/25/08 12:59 PM
Tom,

> That may be significant if you are doing the printf call in a tight loop
> like updating status information.
>
> I'd still be more likely to just use CString::Format or
> CString::FormatMessage and skip printf altogether.  That is a pretty thin
> layer on top of it all.

Well, I can tell you that I often use Format and rarely use printf in a
Windows application!

However, that said, Format is not that thin of a wrapper. It actually parses
the format string twice. The first time is to determine the size of the
required buffer. In fact, last time I looked into this, the code to do this
was not in the C run time, it was actually MFC code that parsed through the
format string, looking at each field and determining its length.

--
Jonathan Wood
SoftCircuits Programming
http://www.softcircuits.com

Re: Pass CString to printf? John Sw 9/25/08 1:40 PM
On 9/25/2008 3:55 PM Jonathan Wood wrote:
> Mark,
>
>>> Is it safe to pass a CString to printf without explicit (LPCTSTR) cast?
>>
>> Yes, and that's how it should be passed - with NO cast.
>>
>> Using the cast will hide a bug if you move the code to a Unicode build.
>
> I must confess that I'm pretty surprised someone would suggest in a
> thread like this that the typecast can cause a bug, and yet not even
> hint at what that bug might be.
>
> I posted that the typecase can be more efficient, and then explained the
> details of why.
>
> Any chance you'll do the same and explain why we should use the less
> efficient syntax?

I won't speak for anyone else, but the danger here isn't in using the
cast (which as you point out is a good idea). It is in using a dumb
cast. It should really use static_cast<LPCTSTR>(), which will not cause
unexpected conversions and is also Unicode safe. The only reason to use
the C-style casts is to save typing, and we know how much time that
saves in the long run.


Re: Pass CString to printf? Mark Salsbery [MVP] 9/25/08 2:13 PM
"Jonathan Wood" <jw...@softcircuits.com> wrote in message
news:#0rjOj0HJHA.4564@TK2MSFTNGP02.phx.gbl...

> Mark,
>
>>> Is it safe to pass a CString to printf without explicit (LPCTSTR) cast?
>>
>> Yes, and that's how it should be passed - with NO cast.
>>
>> Using the cast will hide a bug if you move the code to a Unicode build.
>
> I must confess that I'm pretty surprised someone would suggest in a thread
> like this that the typecast can cause a bug, and yet not even hint at what
> that bug might be.


On a Unicode build, a const wchar_t * would be passed - that would be a bug.
Of course it shouldn't compile I suppose, so I retract my statements.

The entire subject of using CString with printf() is kind of silly IMO, but
this would be a more proper way to pass a CString:

// This should work on Unicode and non-Unicode builds
CString kindOfFruit = _T("bananas");
int      howmany = 25;
printf("You have %d %s", howmany, CT2A(kindOfFruit) );


Typecasts cause LOTS of bugs.

Mark

--
Mark Salsbery
Microsoft MVP - Visual C++

>


> I posted that the typecase can be more efficient, and then explained the
> details of why.
>
> Any chance you'll do the same and explain why we should use the less
> efficient syntax?
>
> --
> Jonathan Wood
> SoftCircuits Programming
> http://www.softcircuits.com
>

Re: Pass CString to printf? Mark Salsbery [MVP] 9/25/08 2:15 PM
I was wrong again - the code I described as a bug (using that cast in a
Unicode build) WOULD compile with no warning/error.
Re: Pass CString to printf? Tom Walker 9/25/08 2:13 PM
"Mark Salsbery [MVP]" <MarkSalsbery[MVP]@newsgroup.nospam> wrote in message
news:#igcYd0HJHA.4240@TK2MSFTNGP02.phx.gbl...

>> Is it safe to pass a CString to printf without explicit (LPCTSTR) cast?
>
> Yes, and that's how it should be passed - with NO cast.
>
> Using the cast will hide a bug if you move the code to a Unicode build.

It's true that C-style casts should be avoided, but a C++ static_cast is
safe:
static_cast<LPCTSTR>(myStr);

However, the CString::GetString method is cleaner:
myStr.GetString();
 

Re: Pass CString to printf? Mark Salsbery [MVP] 9/25/08 2:17 PM
"Tom Walker" <nob...@example.com> wrote in message
news:OD40FO1HJHA.2296@TK2MSFTNGP03.phx.gbl...


My point was Unicode build in this specific instance.  Try the OP's code on
a Unicode build - you'll see what I mean.
A static cast won't fix that - the string needs to be converted to ANSI.

Mark

--
Mark Salsbery
Microsoft MVP - Visual C++


>
>

Re: Pass CString to printf? Mark Salsbery [MVP] 9/25/08 2:34 PM
"John Sw" <jswartzen@noemail.noemail> wrote in message
news:uarui70HJHA.740@TK2MSFTNGP03.phx.gbl...

>
>It should really use static_cast<LPCTSTR>(), which will not cause
>unexpected conversions and is also Unicode safe.


Safe?  Maybe, but it doesn't work, unless the 'b' in the string "bananas" is
all you wanted.  Try it.

Mark

--
Mark Salsbery
Microsoft MVP - Visual C++
 

Re: Pass CString to printf? Jonathan Wood 9/25/08 2:46 PM
Mark,

> On a Unicode build, a const wchar_t * would be passed - that would be a
> bug.
> Of course it shouldn't compile I suppose, so I retract my statements.

Ah... got ya. Personally, I don't consider that a bug in the typecast. But
if you are calling printf in a Unicode app, then you definitely need to know
what you are doing.

> The entire subject of using CString with printf() is kind of silly IMO,
> but this would be a more proper way to pass a CString:
>
> // This should work on Unicode and non-Unicode builds
> CString kindOfFruit = _T("bananas");
> int      howmany = 25;
> printf("You have %d %s", howmany, CT2A(kindOfFruit) );

Sure, but this code would probably be better written to call _tprintf
instead of printf.

--
Jonathan Wood
SoftCircuits Programming
http://www.softcircuits.com

Re: Pass CString to printf? Jonathan Wood 9/25/08 2:49 PM
I must be getting old. I still use the only type of cast available back when
I learned C.

Can anyone tell me the difference, specifically, in the code generated by
the compiler for these two statements?

1. p = static_cast<LPCTSTR>(myStr);
2. p = (LPCTSTR)myStr;

Thanks.

--
Jonathan Wood
SoftCircuits Programming
http://www.softcircuits.com


"Tom Walker" <nob...@example.com> wrote in message
news:OD40FO1HJHA.2296@TK2MSFTNGP03.phx.gbl...

Re: Pass CString to printf? Jonathan Wood 9/25/08 2:51 PM
A cast to LPCTSTR in an argument to printf() in a Unicode build, should
cause a warning/error. In a Unicode build, LPCTSTR is LPCWSTR and printf()
expects LPCSTR.

--
Jonathan Wood
SoftCircuits Programming
http://www.softcircuits.com

"Mark Salsbery [MVP]" <MarkSalsbery[MVP]@newsgroup.nospam> wrote in message
news:OM7FKP1HJHA.4600@TK2MSFTNGP06.phx.gbl...

Re: Pass CString to printf? David Wilkinson 9/25/08 3:03 PM

Mark:

I'm not quite sure what your point is here. If it is that you should always use
_tprintf() or CString::Format() rather than printf(), then I would agree with
you. But surely then it does not matter whether you use the LPCTSTR cast or not.

But suppose you do use printf(). In a Unicode build I can see that you will not
get the answer you expect, but what is the difference between using the LPCTSTR
cast or not?

--
David Wilkinson
Visual C++ MVP

Re: Pass CString to printf? Mark Salsbery [MVP] 9/25/08 3:11 PM
"Jonathan Wood" <jw...@softcircuits.com> wrote in message
news:OaZaRh1HJHA.2156@TK2MSFTNGP05.phx.gbl...

> Mark,
>
>> On a Unicode build, a const wchar_t * would be passed - that would be a
>> bug.
>> Of course it shouldn't compile I suppose, so I retract my statements.
>
> Ah... got ya. Personally, I don't consider that a bug in the typecast.


Whatever :)  The entire statement would cause bug-like behavior at runtime.


> But if you are calling printf in a Unicode app, then you definitely need
> to know what you are doing.


Agreed - I'd go further and state one should know what they're doing when
using CString.

My original main point was really mixing fixed string types with generic
string types is, umm, counterproductive?  It renders the whole usefulness of
generic string types useless.


> Sure, but this code would probably be better written to call _tprintf
> instead of printf.


I totally agree - that's why I mentioned the generic text mappings in my OP
:)

Cheers,
Mark

--
Mark Salsbery
Microsoft MVP - Visual C++


>


> --
> Jonathan Wood
> SoftCircuits Programming
> http://www.softcircuits.com
>

Re: Pass CString to printf? Mark Salsbery [MVP] 9/25/08 3:17 PM
"Jonathan Wood" <jw...@softcircuits.com> wrote in message
news:eXWDyj1HJHA.2580@TK2MSFTNGP05.phx.gbl...

> A cast to LPCTSTR in an argument to printf() in a Unicode build, should
> cause a warning/error. In a Unicode build, LPCTSTR is LPCWSTR and printf()
> expects LPCSTR.
>


That's what I originally thought, but with var args the compiler doesn't
give a warning even at level 4.

Here's my test code for this thread:

//
// Tested on Visual Studio 2008 SP1
//


CString kindOfFruit = _T("bananas");
int      howmany = 25;
char buff[80];
sprintf(buff, "You have %d %s", howmany, CT2A(kindOfFruit) );
sprintf(buff, "You have %d %s", howmany, (LPCTSTR)kindOfFruit );
sprintf(buff, "You have %d %s", howmany, static_cast<LPCTSTR>(kindOfFruit));


No warnings (except the deprecated functions).

Mark

--
Mark Salsbery
Microsoft MVP - Visual C++

Re: Pass CString to printf? Alexander Grigoriev 9/25/08 3:41 PM
Because CString is not a simple type, like an integer or pointer, (LPCTSTR)
cast is only interpreted as static_cast.

"Jonathan Wood" <jw...@softcircuits.com> wrote in message
news:Oc9Rji1HJHA.3868@TK2MSFTNGP04.phx.gbl...

Re: Pass CString to printf? Alexander Grigoriev 9/25/08 3:42 PM
LPCTSTR cast of CString is always safe. There is NO cast to the "other"
string pointer (LPCXSTR) provided by CString; such a cast won't compile.

For CString, C-style LPCTSTR cast (or LPCTSTR(s)) can only be interpreted
one way: by invoking LPCTSTR operator. There is no reinterpret_cast
interpretation for that, because the source is not a builtin type.

"Mark Salsbery [MVP]" <MarkSalsbery[MVP]@newsgroup.nospam> wrote in message
news:OvRpMO1HJHA.4240@TK2MSFTNGP02.phx.gbl...

Re: Pass CString to printf? Alexander Grigoriev 9/25/08 3:42 PM
Why? This is a variadic function, with arguments of any POD type.

"Jonathan Wood" <jw...@softcircuits.com> wrote in message
news:eXWDyj1HJHA.2580@TK2MSFTNGP05.phx.gbl...

Re: Pass CString to printf? Mark Salsbery [MVP] 9/25/08 3:44 PM

"David Wilkinson" <no-r...@effisols.com> wrote in message
news:Ouq4Oq1HJHA.1156@TK2MSFTNGP04.phx.gbl...


>
> Mark:
>
> I'm not quite sure what your point is here. If it is that you should
> always use _tprintf() or CString::Format() rather than printf(), then I
> would agree with you.


That was my point yes.  The mixing of generic and non generic strings is a
peeve of mine.  It's the number one source of string-related bugs IME
looking at people's posted code.

I suppose I should have said nothing.


>
> But suppose you do use printf(). In a Unicode build I can see that you
> will not get the answer you expect, but what is the difference between
> using the LPCTSTR cast or not?


I didn't say there was a difference (I don't think).

Jonathan Wood stated using the cast is more efficient, but I just looked at
the disassembly of my test code (below) and it seems NOT using the cast is
the most efficient.  I could be wrong :)

//
// Test platform:  VS 2008 SP1 on Vista Ultimate
//
//   Unicode build!
//


CString kindOfFruit = _T("bananas");
int      howmany = 25;
char bufff[250];
sprintf(bufff, "You have %d %s", howmany, kindOfFruit);
sprintf(bufff, "You have %d %s", howmany, (LPCTSTR)kindOfFruit );
sprintf(bufff, "You have %d %s", howmany,
static_cast<LPCTSTR>(kindOfFruit));
sprintf(bufff, "You have %d %s", howmany, CT2A(kindOfFruit) );

Mark

--
Mark Salsbery
Microsoft MVP - Visual C++

>


> --
> David Wilkinson
> Visual C++ MVP

Re: Pass CString to printf? Giovanni Dicanio 9/25/08 3:43 PM

"Jonathan Wood" <jw...@softcircuits.com> ha scritto nel messaggio
news:Oc9Rji1HJHA.3868@TK2MSFTNGP04.phx.gbl...

>I must be getting old. I still use the only type of cast available back
>when I learned C.
>
> Can anyone tell me the difference, specifically, in the code generated by
> the compiler for these two statements?
>
> 1. p = static_cast<LPCTSTR>(myStr);
> 2. p = (LPCTSTR)myStr;

I think that, if the class has a operator LPCTSTR() for conversion, like
CString has, these are equivalent.

However, the point is doing:

  CString myStr;

  _tprintf( TEXT("My string: %s"), myStr ); // #1

  vs.

   _tprintf( TEXT("My string: %s"), (LPCTSTR)myStr ); // #2

I believe #2 is equivalent to:

  _tprintf( TEXT("My string: %s"), static_cast< LPCTSTR >(myStr) );

Instead, #1 is possible thanks to CStringT/CSimpleStringT memory layout,
that I tryed to explain in my first post, and is confirmed also by this
working code:

 CString str = TEXT("ciao");
 const TCHAR * psz = *reinterpret_cast< const TCHAR ** >(&str);

the debugger shows "ciao" for 'psz'.

Giovanni


Re: Pass CString to printf? Mark Salsbery [MVP] 9/25/08 3:52 PM
"Alexander Grigoriev" <al...@earthlink.net> wrote in message
news:#H7kMA2HJHA.2272@TK2MSFTNGP04.phx.gbl...
> LPCTSTR cast of CString is always safe. There is NO cast to the "other"
> string pointer (LPCXSTR) provided by CString; such a cast won't compile.
>
> For CString, C-style LPCTSTR cast (or LPCTSTR(s)) can only be interpreted
> one way: by invoking LPCTSTR operator. There is no reinterpret_cast
> interpretation for that, because the source is not a builtin type.
>


Ok.  I'm not sure how any of that applies to and/or contradicts any
statements I made  :)

The cast is is not only perfectly fine in the OP's case, but it isn't even
necessary.


My point was that it would not give the desired results on a Unicode build.

IMO either use generic types (e.g. TCHAR, CString, generic-text mapped
functions) everywhere or use specific types (e.g. CStringA, CStringT, char,
printf()).

Mixing them makes non-portable code and introduces undesired behavior, as
demonstrated by the OP's code built with UNICODE/_UNICODE defined.


Mark

--
Mark Salsbery
Microsoft MVP - Visual C++
 

Re: Pass CString to printf? Jonathan Wood 9/25/08 5:15 PM
Doh! You're right. The format string must be the right type, but any
additional arguments are untyped.

'scuse me.

--
Jonathan Wood
SoftCircuits Programming
http://www.softcircuits.com

"Mark Salsbery [MVP]" <MarkSalsbery[MVP]@newsgroup.nospam> wrote in message
news:ulD3Ey1HJHA.4084@TK2MSFTNGP04.phx.gbl...
> "Jonathan Wood" <jw...@softcircuits.com> wrote in message
> news:eXWDyj1HJHA.2580@TK2MSFTNGP05.phx.gbl...
>> A cast to LPCTSTR in an argument to printf() in a Unicode build, should
>> cause a warning/error. In a Unicode build, LPCTSTR is LPCWSTR and
>> printf() expects LPCSTR.
>>
>
>
> That's what I originally thought, but with var args the compiler doesn't
> give a warning even at level 4.
>
> Here's my test code for this thread:
>
> //
> // Tested on Visual Studio 2008 SP1
> //
> CString kindOfFruit = _T("bananas");
> int      howmany = 25;
> char buff[80];
> sprintf(buff, "You have %d %s", howmany, CT2A(kindOfFruit) );
> sprintf(buff, "You have %d %s", howmany, (LPCTSTR)kindOfFruit );
> sprintf(buff, "You have %d %s", howmany,
> static_cast<LPCTSTR>(kindOfFruit));
>
>
> No warnings (except the deprecated functions).


>
> Mark
>
> --
> Mark Salsbery
> Microsoft MVP - Visual C++

Re: Pass CString to printf? Jonathan Wood 9/25/08 5:16 PM
So, if I follow, it doesn't matter in this case. Which is what I was
thinking.

--
Jonathan Wood
SoftCircuits Programming
http://www.softcircuits.com

"Alexander Grigoriev" <al...@earthlink.net> wrote in message
news:OVaNc$1HJHA.5060@TK2MSFTNGP02.phx.gbl...
> Because CString is not a simple type, like an integer or pointer,
> (LPCTSTR) cast is only interpreted as static_cast.


>
> "Jonathan Wood" <jw...@softcircuits.com> wrote in message
> news:Oc9Rji1HJHA.3868@TK2MSFTNGP04.phx.gbl...
>>I must be getting old. I still use the only type of cast available back
>>when I learned C.
>>
>> Can anyone tell me the difference, specifically, in the code generated by
>> the compiler for these two statements?
>>
>> 1. p = static_cast<LPCTSTR>(myStr);
>> 2. p = (LPCTSTR)myStr;
>>
>> Thanks.

>>
>> --
>> Jonathan Wood
>> SoftCircuits Programming
>> http://www.softcircuits.com
>>
>>
>> "Tom Walker" <nob...@example.com> wrote in message
>> news:OD40FO1HJHA.2296@TK2MSFTNGP03.phx.gbl...

>>> "Mark Salsbery [MVP]" <MarkSalsbery[MVP]@newsgroup.nospam> wrote in
>>> message news:#igcYd0HJHA.4240@TK2MSFTNGP02.phx.gbl...
>>>
>>>>> Is it safe to pass a CString to printf without explicit (LPCTSTR)
>>>>> cast?
>>>>
>>>> Yes, and that's how it should be passed - with NO cast.
>>>>
>>>> Using the cast will hide a bug if you move the code to a Unicode build.
>>>
>>> It's true that C-style casts should be avoided, but a C++ static_cast is
>>> safe:
>>> static_cast<LPCTSTR>(myStr);
>>>
>>> However, the CString::GetString method is cleaner:
>>> myStr.GetString();
>>>
>>>
>>
>
>

Re: Pass CString to printf? Jonathan Wood 9/25/08 5:16 PM
Yes, I've already been corrected on this. The format string must be of the
correct type, but all arguments after that are untyped.

--
Jonathan Wood
SoftCircuits Programming
http://www.softcircuits.com

"Alexander Grigoriev" <al...@earthlink.net> wrote in message
news:eWszJA2HJHA.788@TK2MSFTNGP06.phx.gbl...
> Why? This is a variadic function, with arguments of any POD type.

>
> "Jonathan Wood" <jw...@softcircuits.com> wrote in message
> news:eXWDyj1HJHA.2580@TK2MSFTNGP05.phx.gbl...
>>A cast to LPCTSTR in an argument to printf() in a Unicode build, should
>>cause a warning/error. In a Unicode build, LPCTSTR is LPCWSTR and printf()
>>expects LPCSTR.
>>
>> --
>> Jonathan Wood
>> SoftCircuits Programming
>> http://www.softcircuits.com
>>
>> "Mark Salsbery [MVP]" <MarkSalsbery[MVP]@newsgroup.nospam> wrote in
>> message news:OM7FKP1HJHA.4600@TK2MSFTNGP06.phx.gbl...
>>>I was wrong again - the code I described as a bug (using that cast in a
>>>Unicode build) WOULD compile with no warning/error.

>>>
>>> Mark
>>>
>>> --
>>> Mark Salsbery
>>> Microsoft MVP - Visual C++
>>
>
>

Re: Pass CString to printf? Alexander Grigoriev 9/25/08 5:23 PM
Passing non-POD to a variadic function is not valid C++. Microsoft CSTring
documentation EXPLICITLY says that you need LPCTSTR cast.

"Mark Salsbery [MVP]" <MarkSalsbery[MVP]@newsgroup.nospam> wrote in message
news:OlJVjF2HJHA.2492@TK2MSFTNGP05.phx.gbl...

> "Alexander Grigoriev" <al...@earthlink.net> wrote in message
> news:#H7kMA2HJHA.2272@TK2MSFTNGP04.phx.gbl...
>> LPCTSTR cast of CString is always safe. There is NO cast to the "other"
>> string pointer (LPCXSTR) provided by CString; such a cast won't compile.
>>
>> For CString, C-style LPCTSTR cast (or LPCTSTR(s)) can only be interpreted
>> one way: by invoking LPCTSTR operator. There is no reinterpret_cast
>> interpretation for that, because the source is not a builtin type.
>>
>
>
> Ok.  I'm not sure how any of that applies to and/or contradicts any
> statements I made  :)
>
> The cast is is not only perfectly fine in the OP's case, but it isn't even
> necessary.
>
>
> My point was that it would not give the desired results on a Unicode
> build.
>

Both cast and non-cast won't magically make the argument with the necessary
type. Such is danger of printf and alike functions.


Re: Pass CString to printf? Jonathan Wood 9/25/08 5:23 PM
Mark,

> Jonathan Wood stated using the cast is more efficient, but I just looked
> at the disassembly of my test code (below) and it seems NOT using the cast
> is the most efficient.  I could be wrong :)

Some time ago, I looked into this. At that time, passing a CString object
untyped to _tprintf() caused a copy of the CString to be created and then
passed to _tprintf(). It still works because of the memory layout. On the
other hand, passing the address of the string withing the CString object
requires no memory to be copied.

I suppose it's possible this has changed but I strongly suspect it has not.
If you have something that shows the typecast is not more efficent, please
share.

--
Jonathan Wood
SoftCircuits Programming
http://www.softcircuits.com

Re: Pass CString to printf? David Wilkinson 9/25/08 6:11 PM
Mark Salsbery [MVP] wrote:
> Jonathan Wood stated using the cast is more efficient, but I just looked
> at the disassembly of my test code (below) and it seems NOT using the
> cast is the most efficient.  I could be wrong :)
>
> //
> // Test platform:  VS 2008 SP1 on Vista Ultimate
> //
> //   Unicode build!

> //
> CString kindOfFruit = _T("bananas");
> int      howmany = 25;
> char bufff[250];
> sprintf(bufff, "You have %d %s", howmany, kindOfFruit);
> sprintf(bufff, "You have %d %s", howmany, (LPCTSTR)kindOfFruit );
> sprintf(bufff, "You have %d %s", howmany, static_cast<LPCTSTR>(kindOfFruit));
> sprintf(bufff, "You have %d %s", howmany, CT2A(kindOfFruit) );

Mark:

Maybe the assembly is not exactly the same, but don't the first three all give
the same "wrong" result, but without doing any actual conversion or memory
allocation?

While the last gives the "right" result, at the cost of a conversion (and a
memory allocation if the string is big enough).

--
David Wilkinson
Visual C++ MVP

Re: Pass CString to printf? Mark Salsbery [MVP] 9/25/08 6:16 PM
"Jonathan Wood" <jw...@softcircuits.com> wrote in message
news:OvPox42HJHA.1304@TK2MSFTNGP02.phx.gbl...
> Mark,

>
> Some time ago, I looked into this. At that time, passing a CString object
> untyped to _tprintf() caused a copy of the CString to be created and then
> passed to _tprintf(). It still works because of the memory layout. On the
> other hand, passing the address of the string withing the CString object
> requires no memory to be copied.
>
> I suppose it's possible this has changed but I strongly suspect it has
> not. If you have something that shows the typecast is not more efficent,
> please share.


I posted the code along with my test platform info in the post you responded
to here.

I'm not agreeing or disagreeing with your comments.
I just looked at the disassembly of a non-optimized build of the code I
posted and it looked like not using the cast was the most efficient.
I also said I may be wrong.  I'll leave it for someone else to
prove/disprove.

Mark

--
Mark Salsbery
Microsoft MVP - Visual C++


>


> --
> Jonathan Wood
> SoftCircuits Programming
> http://www.softcircuits.com
>

Re: Pass CString to printf? Mark Salsbery [MVP] 9/25/08 6:26 PM
"Jonathan Wood" <jw...@softcircuits.com> wrote in message
news:OvPox42HJHA.1304@TK2MSFTNGP02.phx.gbl...
>
> If you have something that shows the typecast is not more efficent, please
> share.

Here's what I see - VC 9 compiler, debug build, no optimizations.
Without cast and with...

sprintf(bufff, "You have %d %s", howmany, kindOfFruit);
00420E5A  mov         esi,esp
00420E5C  mov         eax,dword ptr [ebp-24h]
00420E5F  push        eax
00420E60  mov         ecx,dword ptr [ebp-30h]
00420E63  push        ecx
00420E64  push        offset string "You have %d %s" (446B88h)
00420E69  lea         edx,[ebp-134h]
00420E6F  push        edx
00420E70  call        dword ptr [__imp__sprintf (0A1E650h)]
00420E76  add         esp,10h
00420E79  cmp         esi,esp
00420E7B  call        @ILT+5270(__RTC_CheckEsp) (41649Bh)


sprintf(bufff, "You have %d %s", howmany, (LPCTSTR)kindOfFruit );
00420E80  mov         esi,esp
00420E82  lea         ecx,[ebp-24h]
00420E85  call        dword ptr
[__imp_ATL::CSimpleStringT<wchar_t,1>::operator wchar_t const * (0A1EB98h)]
00420E8B  cmp         esi,esp
00420E8D  call        @ILT+5270(__RTC_CheckEsp) (41649Bh)
00420E92  mov         esi,esp
00420E94  push        eax
00420E95  mov         eax,dword ptr [ebp-30h]
00420E98  push        eax
00420E99  push        offset string "You have %d %s" (446B88h)
00420E9E  lea         ecx,[ebp-134h]
00420EA4  push        ecx
00420EA5  call        dword ptr [__imp__sprintf (0A1E650h)]
00420EAB  add         esp,10h
00420EAE  cmp         esi,esp
00420EB0  call        @ILT+5270(__RTC_CheckEsp) (41649Bh)


I'm open to any interpretation of which is more efficient :)

Mark

--
Mark Salsbery
Microsoft MVP - Visual C++

Re: Pass CString to printf? Mark Salsbery [MVP] 9/25/08 6:46 PM
"David Wilkinson" <no-r...@effisols.com> wrote in message
news:uCw5#S3HJHA.2580@TK2MSFTNGP05.phx.gbl...

> Mark:
>
> Maybe the assembly is not exactly the same, but don't the first three all
> give the same "wrong" result, but without doing any actual conversion or
> memory allocation?
>
> While the last gives the "right" result, at the cost of a conversion (and
> a memory allocation if the string is big enough).


Sure.

I just threw the code out there (based on the OP's code) for anyone In this
discussion to test with.

I did all four to test the validity of the efficiency comments.
The static_cast version assembly is identical to the C-style cast.
And yes, the one that does the conversion takes the most instructions but
yields the correct result on a Unicode build.

I'm really not sure what's being discussed at this point - I only originally
meant to respond to the OP.

Mark

--
Mark Salsbery
Microsoft MVP - Visual C++


> --
> David Wilkinson
> Visual C++ MVP

Re: Pass CString to printf? Jonathan Wood 9/25/08 6:48 PM
Yep. In your example, the typecast version calls the LPCTSTR operation
method, which is less efficient.

Note that this will not happen in a release build. However, I did a test of
my own and looked at the release code. It looks like the CString object is
not copied as I had earlier observed.

Therefore, in this partiuclar example (my test used _tprintf()), there
doesn't appear to be any difference between passing the CString object with
and without a typecast as an untyped argument.

--
Jonathan Wood
SoftCircuits Programming
http://www.softcircuits.com

"Mark Salsbery [MVP]" <MarkSalsbery[MVP]@newsgroup.nospam> wrote in message
news:ujW4sb3HJHA.1160@TK2MSFTNGP05.phx.gbl...

Re: Pass CString to printf? Mark Salsbery [MVP] 9/25/08 7:22 PM
"Jonathan Wood" <jw...@softcircuits.com> wrote in message
news:#CFwRo3HJHA.5060@TK2MSFTNGP02.phx.gbl...

>
> Note that this will not happen in a release build. However, I did a test
> of my own and looked at the release code. It looks like the CString object
> is not copied as I had earlier observed.
>
> Therefore, in this partiuclar example (my test used _tprintf()), there
> doesn't appear to be any difference between passing the CString object
> with and without a typecast as an untyped argument.
>

Confirmed.

sprintf(bufff, "You have %d %s", howmany, kindOfFruit);
00405596  mov         eax,dword ptr [ebp-1B8h]
0040559C  push        eax
0040559D  mov         ecx,dword ptr [ebp-308h]
004055A3  push        ecx
004055A4  push        413590h
004055A9  lea         edx,[ebp-814h]
004055AF  push        edx
004055B0  call        dword ptr [__imp__sprintf (4111E4h)]
004055B6  add         esp,10h

sprintf(bufff, "You have %d %s", howmany, (LPCTSTR)kindOfFruit );
004055B9  lea         ecx,[ebp-1B8h]
004055BF  call        dword ptr
[__imp_ATL::CSimpleStringT<wchar_t,1>::operator wchar_t const * (411838h)]
004055C5  push        eax
004055C6  mov         eax,dword ptr [ebp-308h]
004055CC  push        eax
004055CD  push        4135A0h
004055D2  lea         ecx,[ebp-814h]
004055D8  push        ecx
004055D9  call        dword ptr [__imp__sprintf (4111E4h)]
004055DF  add         esp,10h


Good to know.  I appreciate the discussion, thanks!!

Cheers,


Mark

--
Mark Salsbery
Microsoft MVP - Visual C++
 

RE: Pass CString to printf? Hannes 9/26/08 12:36 AM
Our team has a million lines of source code to maintain; replacing printf
with Format, or even using typecasts with printf, is not an easy task. My
original post seeks a safe middle-way to use while our code is in a mixed
stage of CString and char*.

We know now that we'll be pretty safe either way.

I thank you all for your efforts and valuable inputs on this matter!!

Cheers,

        / Hannes.

"Hannes" wrote:

> Hi,
>
> Is it safe to pass a CString to printf without explicit (LPCTSTR) cast?
>
> The following MSDN article suggests it is NOT safe:
> http://msdn.microsoft.com/en-us/library/awkwbzyc(VS.71).aspx
> "...it is essential that you use an explicit type cast when passing a
> CString object to a function that takes a variable number of arguments.
> ...
> CString kindOfFruit = "bananas";
> int      howmany = 25;
> printf( "You have %d %s\n", howmany, (LPCTSTR)kindOfFruit );"
>
>
> On the other hand, various newsgroup posts claim that CString was designed
> specifically in such a way that the (LPCTSTR) cast would not be needed with
> printf.
>
> We are a team of 40+ developers who are converting several large projects
> from char* to CString, and avoiding (LPCTSTR) would save us a lot of time.
>
> Can someone with insight please clarify what the software developing
> community should do in this case?
>
> Thanks,
>
>         / Hannes.

Re: Pass CString to printf? David Wilkinson 9/26/08 3:53 AM
Mark Salsbery [MVP] wrote:
> I just threw the code out there (based on the OP's code) for anyone In
> this discussion to test with.
>
> I did all four to test the validity of the efficiency comments.
> The static_cast version assembly is identical to the C-style cast.
> And yes, the one that does the conversion takes the most instructions
> but yields the correct result on a Unicode build.
>
> I'm really not sure what's being discussed at this point - I only
> originally meant to respond to the OP.


Mark:

I'm not quite sure either...

I certainly agree with you that mixed char/TCHAR code is a major source of
confusion and error.

--
David Wilkinson
Visual C++ MVP

Re: Pass CString to printf? John Sw 9/26/08 9:09 AM
On 9/25/2008 5:34 PM Mark Salsbery [MVP] wrote:
> "John Sw" <jswartzen@noemail.noemail> wrote in message
> news:uarui70HJHA.740@TK2MSFTNGP03.phx.gbl...
>>
>> It should really use static_cast<LPCTSTR>(), which will not cause
>> unexpected conversions and is also Unicode safe.
>
>
> Safe?  Maybe, but it doesn't work, unless the 'b' in the string
> "bananas" is all you wanted.  Try it.

You're right and I wasn't thinking. The cast is Unicode safe, but it
isn't correct when you are calling a non-Unicode function. I'll still
stand by the fact that you should use C++ casts, not C casts and you
should cast varargs arguments if you want to be sure you get what you
want. If the type is known, unnecessary casts of any type are a bad idea.

Re: Pass CString to printf? John Sw 9/26/08 9:16 AM
On 9/25/2008 5:49 PM Jonathan Wood wrote:
> I must be getting old. I still use the only type of cast available back
> when I learned C.
>
> Can anyone tell me the difference, specifically, in the code generated
> by the compiler for these two statements?
>
> 1. p = static_cast<LPCTSTR>(myStr);
> 2. p = (LPCTSTR)myStr;
>
> Thanks.

In this case, there should be no difference. The problem is that the
(LPCTSTR) cast might be doing any of three different types of casts
(changing type, safe conversions, const casting) all at the same time
and they might not all be what you want. In some cases using this type
of cast instead of a dynamic_cast can result in you getting the wrong
pointer to an object (e.g., with multiple inheritance).

I'm definitely getting old, but one thing I've learned in the last
twenty plus years is that code generation is only a small part of what
we need to be concerned about.

Re: Pass CString to printf? Joseph M. Newcomer 9/26/08 9:55 AM
The bug is not related to the cast at all.  Whether the cast is present or not, passing a
pointer to a Unicode string to a printf (which uses 8-bit characters) is going to produce
incorrect output if compiled for Unicode.
                                joe

On Thu, 25 Sep 2008 13:55:55 -0600, "Jonathan Wood" <jw...@softcircuits.com> wrote:

>Mark,


>
>>> Is it safe to pass a CString to printf without explicit (LPCTSTR) cast?
>>
>> Yes, and that's how it should be passed - with NO cast.
>>
>> Using the cast will hide a bug if you move the code to a Unicode build.
>
>I must confess that I'm pretty surprised someone would suggest in a thread
>like this that the typecast can cause a bug, and yet not even hint at what
>that bug might be.
>
>I posted that the typecase can be more efficient, and then explained the
>details of why.
>
>Any chance you'll do the same and explain why we should use the less
>efficient syntax?
Joseph M. Newcomer [MVP]
email: newc...@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm

Re: Pass CString to printf? Joseph M. Newcomer 9/26/08 10:03 AM
BUt what if the programmer used %S as a formatting string?  Passing an LPCWSTR is
perfectly valid and will work.  There is NO type-checking of the arguments in the ...
part.

%hs always means "8-bit string formatting"; %ls always means "wide-character string
formatting", %S means "the other kind of formatting", that is, it means %hs for a
w-formatting operation and %ls for an a-formatting operation.

So it is always legitimate to write
CStringW s;
s = ...;
printf("%ls", s);
or
printf("%ls", (LPCWSTR)s);

so type-checking makes no sense, since you can't, without parsing the formatting string
(which might not be a compile-time constant) tell what types are required.  So the
compiler simply trusts that you know what you are doing.
                        joe

On Thu, 25 Sep 2008 15:51:26 -0600, "Jonathan Wood" <jw...@softcircuits.com> wrote:

>A cast to LPCTSTR in an argument to printf() in a Unicode build, should
>cause a warning/error. In a Unicode build, LPCTSTR is LPCWSTR and printf()
>expects LPCSTR.
Joseph M. Newcomer [MVP]
email: newc...@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm

Re: Pass CString to printf? Mark Salsbery [MVP] 9/26/08 10:34 AM
"John Sw" <jswartzen@noemail.noemail> wrote in message
news:48DD092A.8050308@noemail.noemail...

> I'll still stand by the fact that you should use C++ casts, not C casts
> and you should cast varargs arguments if you want to be sure you get what
> you want. If the type is known, unnecessary casts of any type are a bad
> idea.


Agreed!

Cheers,
Mark

--
Mark Salsbery
Microsoft MVP - Visual C++

Re: Pass CString to printf? Leo Violette 10/9/08 1:43 PM
Not true.  There are cases where it is perfectly valid to pass a UNICODE
character pointer to a printf style function.

Unless you expect the compiler to parse the format string (the %s's and %d's
and whatnot) to determine what arguments would be
valid and then give a warning if one of those arguments don't match.  I
certainly don't expect that of the compiler.  They would have to update
the compiler everytime some coder decides to enhance the printf style
functions.

printf allows a %S (note capital S).  If it encounters one, then it's
expecting a wchar_t*.
Likewise, if wprintf encounters a %S, it wll expect a char*.
Leo V.

"Jonathan Wood" <jw...@softcircuits.com> wrote in message
news:eXWDyj1HJHA.2580@TK2MSFTNGP05.phx.gbl...

>A cast to LPCTSTR in an argument to printf() in a Unicode build, should
>cause a warning/error. In a Unicode build, LPCTSTR is LPCWSTR and printf()
>expects LPCSTR.
>
> --
> Jonathan Wood
> SoftCircuits Programming
> http://www.softcircuits.com
>
> "Mark Salsbery [MVP]" <MarkSalsbery[MVP]@newsgroup.nospam> wrote in
> message news:OM7FKP1HJHA.4600@TK2MSFTNGP06.phx.gbl...
>>I was wrong again - the code I described as a bug (using that cast in a
>>Unicode build) WOULD compile with no warning/error.
>>
>> Mark
>>
>> --
>> Mark Salsbery
>> Microsoft MVP - Visual C++
>

More topics »