Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

CString not working as advertised

81 views
Skip to first unread message

R. Christian Call

unread,
Apr 19, 2006, 3:06:53 PM4/19/06
to
I recently got hold of a copy of VS 2005, and I've been playing around
with writing a VC++ MFC application that needs to convert some CString
values to C character strings, in order to pass them to a C function.
I'm having trouble doing that, and I can't seem to find good info about
the problem.

The examples given in the MFC library fail miserably most fo the time--
even for simple stuff that I'd expect to work without a hitch. For
instance, I can't do this:

CString kindOfFruit = "bananas";

... because I get "error C2440: 'initializing' : cannot convert from
'const char [8] to 'ATL::CString<BaseType,StringTraits>' etc. etc. etc.

For passing CString to a routine that expects "char *", the
documentation suggests casting to LPCTSTR. But when I try that, I get
error C2664 saying that the compiler can't convert LPCTSTR to 'char *'
because "Types pointed to are unrelated; conversion requires
reinterpret_cast, C-style cast or function-style cast."

No matter what I do, I can't seem to create anything that I can cast to
a 'char *'.

I figure there's got to be something really obvious here that I've
overlooked, but I'm not seeing it. Can anyone help me out?


-- Chris

(Remove the first "i" to reply.)

Mark Randall

unread,
Apr 19, 2006, 3:16:30 PM4/19/06
to
const char* is not what CString has by default in 2005, its const wchar_t*.

Use CStringA (for ASCII, and hence char*) or CStringW (for UNICODE, and
hence wchar_t* ).

If you want to write apps that easily change (why?) then use CString and it
will change between CStringA and CStringW depending upon the UNICODE project
settings (instead of mbcs).

--
- Mark Randall
http://www.temporal-solutions.co.uk

"We're Systems and Networks..."
"It's our job to know..."
"R. Christian Call" <rcc...@optionline.net> wrote in message
news:MPG.1eb05443...@msnews.microsoft.com...

Jonathan Wood

unread,
Apr 19, 2006, 3:42:00 PM4/19/06
to
Go into the Project settings and set the character type to multibyte. By
default, projects compile to use Unicode strings, which are different from
the ones you may be used to.

--
Jonathan Wood
SoftCircuits
http://www.softcircuits.com
Available for consulting: http://www.softcircuits.com/jwood/resume.htm

"R. Christian Call" <rcc...@optionline.net> wrote in message
news:MPG.1eb05443...@msnews.microsoft.com...

Joseph M. Newcomer

unread,
Apr 19, 2006, 4:03:05 PM4/19/06
to
On Wed, 19 Apr 2006 15:06:53 -0400, R. Christian Call <rcc...@optionline.net> wrote:

>I recently got hold of a copy of VS 2005, and I've been playing around
>with writing a VC++ MFC application that needs to convert some CString
>values to C character strings, in order to pass them to a C function.
>I'm having trouble doing that, and I can't seem to find good info about
>the problem.
>
>The examples given in the MFC library fail miserably most fo the time--
>even for simple stuff that I'd expect to work without a hitch. For
>instance, I can't do this:
>
>CString kindOfFruit = "bananas";

****
Note that default for VS 2005 is Unicode, so a quoted string like above is meaningless.
You could either write

CStringA kindOfFruit = "bananans";
or
CStringW kindOfFruit = L"bananas";
or
CString kindOfFruite = _T("bananas");

but what you wrote should not compile, and the error message below is what you should get.
****


>
>... because I get "error C2440: 'initializing' : cannot convert from
>'const char [8] to 'ATL::CString<BaseType,StringTraits>' etc. etc. etc.
>
>For passing CString to a routine that expects "char *", the
>documentation suggests casting to LPCTSTR. But when I try that, I get
>error C2664 saying that the compiler can't convert LPCTSTR to 'char *'
>because "Types pointed to are unrelated; conversion requires
>reinterpret_cast, C-style cast or function-style cast."

****
That's because you are using a Unicode string. If you want a char *, either use CStringA
or use the ATL functions such as T2A to convert a CString to an 8-bit string. So indeed
it is unable to convert a Unicode string to a "char *" because they are incompatible,
which is what the error message tells you.
****


>
>No matter what I do, I can't seem to create anything that I can cast to
>a 'char *'.

****
Sure you can. But since you have a Unicode app, you have to go through one more level of
translation.
****


>
>I figure there's got to be something really obvious here that I've
>overlooked, but I'm not seeing it.

****
Unicode
***


>Can anyone help me out?
>
>
>-- Chris
>
>(Remove the first "i" to reply.)

Joseph M. Newcomer [MVP]
email: newc...@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
--
NewsGuy.Com 30Gb $9.95 Carry Forward and On Demand Bandwidth

R. Christian Call

unread,
Apr 19, 2006, 4:28:33 PM4/19/06
to
Mark,

Thanks for the help. Changing the project settings so that they didn't
specify UNICODE did the trick.

Chris

In article <#jkRTX#YGHA...@TK2MSFTNGP03.phx.gbl>, mark
[__OKTHISISFAKE_]y...@REMOVETHISgoogle.ANDTHIScom says...

Mihai N.

unread,
Apr 20, 2006, 3:51:35 AM4/20/06
to
> Thanks for the help. Changing the project settings so that they didn't
> specify UNICODE did the trick.
Please, follow Joseph M. Newcomer's advice:
especially CString kindOfFruite = _T("bananas");
Sooner or later you will be sorry for not being Unicode!

--
Mihai Nita [Microsoft MVP, Windows - SDK]
http://www.mihai-nita.net
------------------------------------------
Replace _year_ with _ to get the real email

David Wilkinson

unread,
Apr 20, 2006, 5:48:12 AM4/20/06
to
Joseph M. Newcomer wrote:
> On Wed, 19 Apr 2006 15:06:53 -0400, R. Christian Call <rcc...@optionline.net> wrote:
>
>
[snip]

>>
>>The examples given in the MFC library fail miserably most fo the time--
>>even for simple stuff that I'd expect to work without a hitch. For
>>instance, I can't do this:
>>
>>CString kindOfFruit = "bananas";
>
> ****
> Note that default for VS 2005 is Unicode, so a quoted string like above is meaningless.
> You could either write
>
> CStringA kindOfFruit = "bananans";
> or
> CStringW kindOfFruit = L"bananas";
> or
> CString kindOfFruite = _T("bananas");
>
> but what you wrote should not compile, and the error message below is what you should get.
> ****
>
[snip]

Joe:

That's interesting, but I disagree. In VC6, and I think VC7, in a
UNICODE build

CString kindOfFruit = "bananas";

will actually compile, because CString contains "conversion
constructors" which will initialize a CString from either narrow or wide
characters in both ANSI and UNICODE build.

IMO, this is a terrible feature, because (like most automatic
conversions) it prevents the compiler from type-checking the code. But I
find it hard to believe that MS would have removed this feature from
VC8, because much code (not mine!) relies on this feature to convert
between narrow/wide character strings.

David Wilkinson

Alexander Grigoriev

unread,
Apr 20, 2006, 10:43:52 AM4/20/06
to
There is macro that disables implicit conversion (will declare conversion
constructors "explicit"). It may be set by default.

"David Wilkinson" <no-r...@effisols.com> wrote in message
news:%23w1CH%23FZGH...@TK2MSFTNGP03.phx.gbl...

David Wilkinson

unread,
Apr 20, 2006, 10:51:34 AM4/20/06
to
Alexander Grigoriev wrote:

> There is macro that disables implicit conversion (will declare conversion
> constructors "explicit"). It may be set by default.
>

[snip}

Really? I did not know that. What is it called, and which versions of VC
support it?

But sometimes even an explicit conversion constructor is harmful. If you
have an application (I do) where all 8-bit strings are UTF-8 then the
conversion will not do the right thing, because it uses the local code
page. Even worse, the app will appear to work if it uses only ASCII strings.

David Wilkinson

Tom Serface

unread,
Apr 20, 2006, 11:24:51 AM4/20/06
to
Hi David,

I think the bigger issue with this is that it uses the ACP code page
(whatever is set) to do the conversion to multi-byte so you don't always get
a clean conversion. However, to be fair, I find the conversion feature to
be pretty handy at times when I know I am not doing something that would
mangle my strings. You're right though, it doesn't produce any error
message during compile. That makes me wonder how the OP got this error when
he was compiling.

Tom

"David Wilkinson" <no-r...@effisols.com> wrote in message
news:%23w1CH%23FZGH...@TK2MSFTNGP03.phx.gbl...

David Wilkinson

unread,
Apr 20, 2006, 11:37:38 AM4/20/06
to
Tom Serface wrote:

> Hi David,
>
> I think the bigger issue with this is that it uses the ACP code page
> (whatever is set) to do the conversion to multi-byte so you don't always get
> a clean conversion. However, to be fair, I find the conversion feature to
> be pretty handy at times when I know I am not doing something that would
> mangle my strings. You're right though, it doesn't produce any error
> message during compile. That makes me wonder how the OP got this error when
> he was compiling.
>
> Tom

Tom:

Yes, this puzzled me also. Surely Alexander's explicit constructor will
not prevent this usage?

CString kindOfFruit = "bananas";

It would however prevent the even more insidious

CString s2 = _T("Hello");
std::string s1 = " world";
s2 += s1.c_str();

which also compiles in a Unicode build in VC6 (and VC7 I think).

You are right that it is the code page issue which is the problem. If
you do not want to do conversions using the local code page, you're
hosed. IMHO, if you want to convert, you should use the conversion
macros (which are classes in VC7 and above, much better). Say what you
mean (and mean what you say).

David Wilkinson

Tom Serface

unread,
Apr 20, 2006, 11:53:05 AM4/20/06
to
I agree. I find the conversion convenient at times, but it would certainly
be safer to get a compiler warning at least.

Tom

"David Wilkinson" <no-r...@effisols.com> wrote in message

news:%23FWUXBJ...@TK2MSFTNGP03.phx.gbl...

Joseph M. Newcomer

unread,
Apr 21, 2006, 12:04:11 AM4/21/06
to
CString kindOfFruit("bananas");
will compile because there is an overloaded constructor, overloaded for both LPCSTR and
LPCWSTR, and depending on the build, one or the other will do the appropriate conversion.
But the assignment statement doesn't work. I've seen it fail in a lot of programs.
joe

David Wilkinson

unread,
Apr 21, 2006, 8:38:16 AM4/21/06
to
Joseph M. Newcomer wrote:

> CString kindOfFruit("bananas");
> will compile because there is an overloaded constructor, overloaded for both LPCSTR and
> LPCWSTR, and depending on the build, one or the other will do the appropriate conversion.
> But the assignment statement doesn't work. I've seen it fail in a lot of programs.
> joe
>

[snip]

Hi Joe:

Now that IS interesting. In VC7, you are right. The following will not
compile in a UNICODE application:

CString kindOfFruit = "bananas";

However all of the following do:

CString kindOfFruit("bananas");

CString kindOfFruit = CString("bananas");

CString kindOfFruit;
kindOfFruit = "bananas";

CString kindOfFruit;
kindOfFruit += "bananas";

In my ideal world, none of them would compile (and I have fixed my VC6
headers so they don't). But why does the first one not compile? As I
understand it, when you do

CString kindOfFruit = "bananas";

this is not an assignment (though assignment would work!). Rather, the
compiler should first construct a temporary CString using the const
char* constructor, and then initialize kindOfFruit using the copy
constructor. It is also allowed to elide the temporary and use the const
char* constructor directly, provided the first method would have been
legal.

So why doesn't this work? Can it have to do with the fact that CString
is a template class in VC7 onward?

C++ experts?

David Wilkinson

=====================


Doug Harrison [MVP]

unread,
Apr 21, 2006, 9:14:08 AM4/21/06
to
On Fri, 21 Apr 2006 08:38:16 -0400, David Wilkinson <no-r...@effisols.com>
wrote:

>Joseph M. Newcomer wrote:

See if the relevant ctor is declared "explicit". If so, there's your
answer.

--
Doug Harrison
Visual C++ MVP

David Wilkinson

unread,
Apr 21, 2006, 9:56:22 AM4/21/06
to
Doug Harrison [MVP] wrote:

Hi Doug:

In VC7.1, none of the CStringT constructors is explicit (at least in the
documentation). But CStringT is derived from CSimpleStringT, which does
have an explicit constructor:

explicit CSimpleStringT(
IAtlStringMgr* pStringMgr
) throw( );

At this point my head started to spin. What is IAtlStringMgr? Anyway, I
do not see how this explicit declaration discriminates between LPCSTR
and LPCWSTR. Also, does explicit base constructor carry over to the
derived class? CString has gotten very complicated!

IMO, no matter what, MS missed a big opportunity to get rid of all the
conversion constructors when they redesigned the CString class using
templates. They must make the coding of CStringT very complicated. In
the standard library you can just do

typedef std::basic_string<TCHAR> tstring;

and you're done. No conversion constructors, thank you.

David Wilkinson

Tom Serface

unread,
Apr 21, 2006, 10:53:44 AM4/21/06
to
What am I missing? This compiles fine for me:

CString cs = "This is a test";
cs = "This is another test";

In my Unicode application.

Not that I think it should...

Tom

"David Wilkinson" <no-r...@effisols.com> wrote in message

news:eS6wxBUZ...@TK2MSFTNGP04.phx.gbl...

David Wilkinson

unread,
Apr 21, 2006, 11:21:17 AM4/21/06
to
Tom Serface wrote:

> What am I missing? This compiles fine for me:
>
> CString cs = "This is a test";
> cs = "This is another test";
>
> In my Unicode application.
>
> Not that I think it should...
>
> Tom
>

[snip]

Tom!

You have been converted (to non-converting CString). Now we need to work
on top-posting. :-)

What version of VC is this? This does not compile for me on V7.1 with
UNICODE enabled:

CString cs = "This is a test";

I'm pretty sure it did on VC6 before I yanked the conversion
constructors and assignments from my headers. You're using VC8, perhaps?

David Wilkinson

Tom Serface

unread,
Apr 21, 2006, 12:23:04 PM4/21/06
to
I'm using VC++ 2005 (VC8). It's going to be tougher to get me to bottom
post... too much work to post and read imo.

Tom

"David Wilkinson" <no-r...@effisols.com> wrote in message

news:ODxm3cVZ...@TK2MSFTNGP02.phx.gbl...

David Wilkinson

unread,
Apr 21, 2006, 1:28:44 PM4/21/06
to
Tom Serface wrote:

> I'm using VC++ 2005 (VC8). It's going to be tougher to get me to bottom
> post... too much work to post and read imo.
>
> Tom
>
> "David Wilkinson" <no-r...@effisols.com> wrote in message
> news:ODxm3cVZ...@TK2MSFTNGP02.phx.gbl...
>
>
>>You have been converted (to non-converting CString). Now we need to work
>>on top-posting. :-)
>>

Tom:

Oh, well.

That's strange, because the OP was using VS2005 and he said

CString kindOfFruit = "bananas";

would not compile in Unicode build.

David

Doug Harrison [MVP]

unread,
Apr 21, 2006, 4:29:59 PM4/21/06
to
On Fri, 21 Apr 2006 09:56:22 -0400, David Wilkinson <no-r...@effisols.com>
wrote:


>Hi Doug:
>
>In VC7.1, none of the CStringT constructors is explicit (at least in the
>documentation). But CStringT is derived from CSimpleStringT, which does
>have an explicit constructor:
>
>explicit CSimpleStringT(
> IAtlStringMgr* pStringMgr
>) throw( );
>
>At this point my head started to spin. What is IAtlStringMgr? Anyway, I
>do not see how this explicit declaration discriminates between LPCSTR
>and LPCWSTR. Also, does explicit base constructor carry over to the
>derived class? CString has gotten very complicated!

Ctors aren't inherited, so this couldn't be a factor. I seem to think
IAtlStringMgr may be an allocator of some kind, but I haven't looked at it
closely.

>IMO, no matter what, MS missed a big opportunity to get rid of all the
>conversion constructors when they redesigned the CString class using
>templates. They must make the coding of CStringT very complicated. In
>the standard library you can just do
>
>typedef std::basic_string<TCHAR> tstring;
>
>and you're done. No conversion constructors, thank you.

Yes, I've followed your comments for some time on that subject, and you've
convinced me they're evil. There I was thinking CString was *nice* to
provide a ctor for LPCSTR in Unicode builds, even better than tstring in
this respect. :)

Frederico Pissarra

unread,
Apr 21, 2006, 9:59:19 PM4/21/06
to

"R. Christian Call" <rcc...@optionline.net> wrote in message
news:MPG.1eb05443...@msnews.microsoft.com...

> CString kindOfFruit = "bananas";
>
> ... because I get "error C2440: 'initializing' : cannot convert from
> 'const char [8] to 'ATL::CString<BaseType,StringTraits>' etc. etc. etc.
>

You can always construct your CString objects this way:

CString kindOfFruit("bananas");

But, probably you are getting this error 'cause you are not using the
correct "character type".
VC++ 8 projects defaults do UNICODE or Wide String instead of Ansi String.
So, use the _T() macro defined in <tchar.h>:

CString kindOfFunc(_T("bananas"));

this will ensure that you are using the right "character type"... Or, change
your project options to deal only with ANSI strings...

[]s
Fred

Joseph M. Newcomer

unread,
Apr 22, 2006, 1:32:58 AM4/22/06
to
The Good News: in MFC7 you can have both Unicode and ANSI CStrings. The Bad News: you
can't figure out how CString works at all! (Actually, I've been through the exercise a
couple times. It is very difficult to track all the various types, templates, etc., but
with a lot of effort I can usually figure out enough to figure out what went wrong.
Sometimes).

I've seen the failure when converting existing client code which was not written
Unicode-aware to Unicode. Usually when there is some odd reason my pattern-matcher missed
the assignment.
joe

Tom Serface

unread,
Apr 24, 2006, 2:41:20 PM4/24/06
to
I can't answer that one... I just know it compiles and works for me :o(

Tom

"David Wilkinson" <no-r...@effisols.com> wrote in message

news:uWvbFkWZ...@TK2MSFTNGP02.phx.gbl...

Frederico Pissarra

unread,
Apr 24, 2006, 11:47:14 PM4/24/06
to

"Tom Serface" <tser...@msn.com> wrote in message
news:eG7jt68Z...@TK2MSFTNGP02.phx.gbl...

Hummm... I'm not sure, but maybe "bananas" is a ANSI version of the
string...

CString kindOfFruit = L"bananas";

[]s
Fred


Tom Serface

unread,
Apr 25, 2006, 11:16:14 AM4/25/06
to
Hi Frederico,

I think that is true too, but the original thought was that the new compiler
would gripe if we tried to do this thing rather than just converting the
ANSI string. I was saying it still doesn't, at least for me. The OP said
he got a compile error on a similar statement.

Tom

"Frederico Pissarra" <m...@nowhere.net> wrote in message
news:uNpBgtBa...@TK2MSFTNGP05.phx.gbl...

0 new messages