How come I can do this:

char value = '\v';
char c;
unsigned char uc;
signed char sc;

c = value;
uc = value;
sc = value;

But not this:

const char * string = "A string";
const char * c_string;
const unsigned char * uc_string;
const signed char * sc_string;

c_string = string; // this works fine
uc_string = string; // error: can't assign "const char *" to "const
unsigned char *"
sc_string = string; // error: can't assign "const char *" to "const
signed char *"

Re: const char assignments by MrAsm

MrAsm
Tue May 29 10:27:47 CDT 2007

On Tue, 29 May 2007 08:14:33 PDT, LarryW <lwdaddio@newsgroups.nospam>
wrote:


> const char * string = "A string";
> const char * c_string;
> const unsigned char * uc_string;
> const signed char * sc_string;
>
> c_string = string; // this works fine
> uc_string = string; // error: can't assign "const char *" to "const
>unsigned char *"
> sc_string = string; // error: can't assign "const char *" to "const
>signed char *"
>

Try casting:

uc_string = (const unsigned char *) string;
sc_string = (const signed char *) string;

MrAsm

Re: const char assignments by LarryW

LarryW
Tue May 29 10:44:34 CDT 2007

In article <fhho53phd5hsu711ndll0pef4mfl7fk522@4ax.com>, MrAsm wrote:
> From: MrAsm <mrasm@usa.com>
> Newsgroups: microsoft.public.vc.language
> Subject: Re: const char assignments
> Date: Tue, 29 May 2007 15:27:47 GMT
>
> On Tue, 29 May 2007 08:14:33 PDT, LarryW <lwdaddio@newsgroups.nospam>
> wrote:
>
> > const char * string = "A string";
> > const char * c_string;
> > const unsigned char * uc_string;
> > const signed char * sc_string;
> >
> > c_string = string; // this works fine
> > uc_string = string; // error: can't assign "const char *" to "const
> >unsigned char *"
> > sc_string = string; // error: can't assign "const char *" to "const
> >signed char *"
> >
>
> Try casting:
>
> uc_string = (const unsigned char *) string;
> sc_string = (const signed char *) string;
>
> MrAsm
>
Yes, I know that I can cast it away but I was wondering why I need to?


Re: const char assignments by Alex

Alex
Tue May 29 10:45:12 CDT 2007

LarryW wrote:
> How come I can do this:
>
> char value = '\v';
> char c;
> unsigned char uc;
> signed char sc;
>
> c = value;
> uc = value;
> sc = value;
>
> But not this:
>
> const char * string = "A string";
> const char * c_string;
> const unsigned char * uc_string;
> const signed char * sc_string;
>
> c_string = string; // this works fine
> uc_string = string; // error: can't assign "const char *" to "const
> unsigned char *"
> sc_string = string; // error: can't assign "const char *" to "const
> signed char *"

Because `char' is neither signed nor unsigned. When you
assign `char' value to signed/unsigned, then compiler
implicitly converts it to destination type (this process is
called "integral conversion"). However, implicit conversion
isn't performed with pointer types (except conversion to
`void*' type and derived to base class pointers). That's why
you need to cast pointer types explicitly.

Alex


Re: const char assignments by Ulrich

Ulrich
Wed May 30 00:54:56 CDT 2007

LarryW wrote:
> In article <fhho53phd5hsu711ndll0pef4mfl7fk522@4ax.com>, MrAsm wrote:
>> On Tue, 29 May 2007 08:14:33 PDT, LarryW <lwdaddio@newsgroups.nospam>
>> wrote:
>>
>> > const char * string = "A string";
>> > const char * c_string;
>> > const unsigned char * uc_string;
>> > const signed char * sc_string;
>> >
>> > c_string = string; // this works fine
>> > uc_string = string; // error: can't assign "const char *" to "const
>> >unsigned char *"
>> > sc_string = string; // error: can't assign "const char *" to "const
>> >signed char *"
>> >
>>
>> Try casting:
>>
>> uc_string = (const unsigned char *) string;
>> sc_string = (const signed char *) string;
>>
>> MrAsm
>>
> Yes, I know that I can cast it away but I was wondering why I need to?

You don't, you just have to use the right datatype. Other than that, the
advise to cast in general and in C++ the advise to use C-style casts is
utter nonsense. For your own sake, don't do that.

Other than that, if Alex' explanation doesn't help, I'd offer another: In
the case of plain signed char vs unsigned char, you have simple integral
values that can be converted to each other. In the case of pointers, you
have the pointer value, which usually could be converted, and the stuff it
points to. Its the stuff it points to which would also have to be
converted, but that isn't feasible, after all the compiler can't know if
that memory was allocated using new/malloc or on the stack or as part of an
aggregate. Further, it wouldn't make sense either, because that would mean
that 'uc_string' and 'string' would modify different memory areas and
changes in one wouldn't be reflected in the other.

HTH

Uli


Re: const char assignments by MrAsm

MrAsm
Wed May 30 02:57:26 CDT 2007

On Wed, 30 May 2007 07:54:56 +0200, Ulrich Eckhardt
<eckhardt@satorlaser.com> wrote:


>You don't, you just have to use the right datatype. Other than that, the
>advise to cast in general and in C++ the advise to use C-style casts is
>utter nonsense. For your own sake, don't do that.

There are cases in which casting is a must (e.g. storing pointer to
objects using ::SetWindowLongPtr, etc.).

MrAsm

Re: const char assignments by MrAsm

MrAsm
Wed May 30 04:09:20 CDT 2007

On Wed, 30 May 2007 07:54:56 +0200, Ulrich Eckhardt
<eckhardt@satorlaser.com> wrote:


>>> Try casting:
>>>
>>> uc_string = (const unsigned char *) string;
>>> sc_string = (const signed char *) string;
>>>
>>> MrAsm
>>>

>the
>advise to cast in general and in C++ the advise to use C-style casts is
>utter nonsense. For your own sake, don't do that.


Those sentences to me are similar to "rules" like "don't use continue
in a for loop" or "the function must have only one exit point", and
similar things.

This is the assembly code that compiler produced in the "utter
nonsense" of C-style casts, and in the "elegant" (I would say: too
much verbose and bloated) C++ guru style cast:


const unsigned char * u = (const unsigned char *) str;
004199EF mov eax,dword ptr [str]
004199F5 mov dword ptr [u],eax


const unsigned char * u1 = reinterpret_cast<const unsigned
char *>( str );
00419A07 mov eax,dword ptr [str]
00419A0D mov dword ptr [u1],eax


The assembly code is the *same*, the compiler is smart enough to
understand what I want from the C-style cast, and the C++
reinterpret_cast<...> thing is just longer and more bloated.

Maybe the only reason to use C++ modern style casts is on dynamic_cast
and very complex class hierarchies, but it is a thing like Boost or
advanced templates, above my head :)

So, for "trivial" casts like the OP asked, the C-style cast is just
fine for me, IMHO.

(Then, of course, I agree that if a code has too much casts, maybe
something could be wrong; but the OP question was just about a casting
example.)

MrAsm

Re: const char assignments by Eberhard

Eberhard
Wed May 30 04:28:52 CDT 2007

MrAsm write:

> The assembly code is the *same*, the compiler is smart enough to
> understand what I want from the C-style cast, and the C++
> reinterpret_cast<...> thing is just longer and more bloated.

The generated assembly code is the same. But we're not programming
assembly, for good reason.

Casts can be dangerous, I think we can agree to that. C had only one
type of cast, which turned out as a disadvantage. C++ has differentiated
casts:

1) You can tell the compiler more precisely what you want to
achieve, and the compiler can tell you better whether you actually wrote
down what you meant to write. E.g. you might "only" want to cast away a
"const" (e.g. when using a legacy library), you can tell the compiler
so. If, by accident, your cast does something in addition to that, the
compiler will tell you so.

2) Casts can be hard to read. When you revise the code, you can
tell more quickly what is happening with C++ style casts. With a
const_cast you know that only a qualifier can be changed. A
reinterpret_cast is likely to be more fundamental, and so on.

The generated assembly code may be the same. But that's not the point at
all.

Re: const char assignments by MrAsm

MrAsm
Wed May 30 05:29:10 CDT 2007

On Wed, 30 May 2007 11:28:52 +0200, Eberhard Schefold
<eberhard.schefold@de.bosch.com> wrote:

>MrAsm write:
>
>> The assembly code is the *same*, the compiler is smart enough to
>> understand what I want from the C-style cast, and the C++
>> reinterpret_cast<...> thing is just longer and more bloated.
>
>The generated assembly code is the same. But we're not programming
>assembly, for good reason.
>

I showed that generated assembly code is the same to show that there
is no run-time check or other difference between my "utter nonsense"
and the C++ style cast.


>Casts can be dangerous, I think we can agree to that.

Yes, we agree.

But sometimes they are necessary or useful.

For example, when using QueryInterface(), I use the C style (void **)
cast for the 'ppvObject' argument:

HRESULT QueryInterface(
REFIID iid,
void ** ppvObject
);


Maybe some C++ guru would prefer using reinterpret_cast (or other form
of C++ cast), but I like more the C style cast in this case, because I
find it leaner, not bloated, and also I find C style cast easy to read
in this case.

Another example would be for inserting items in CListCtrl's:

<CODE url="http://www.codeproject.com/listctrl/listctrldemo.asp">

// Use the LV_ITEM structure to insert the items
LVITEM lvi;
CString strItem;
for (int i = 0; i < m_nItems; i++)
{
// Insert the first item
lvi.mask = LVIF_IMAGE | LVIF_TEXT;
strItem.Format(_T("Item %i"), i);
lvi.iItem = i;
lvi.iSubItem = 0;
lvi.pszText = (LPTSTR)(LPCTSTR)(strItem);

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
CAST HERE
...

}
</CODE>

I find no problem in using these kinds of C style casts.

Of course, I respect who prefers the C++ style casts (which I found
more verbose and bloated in these contexts, but in other more complex
contexts I think that C++ casts like dynamic_cast might be necessary).

I just don't consider the C style cast a "utter nonsense", and I
believe that banning C style casts is like banning 'continue' in for
loops or having rules like "functions must have only one exit point"
and similar things.

However, I would like to stop here to avoid flames :)
I hope I made my point clear.

MrAsm

Re: const char assignments by Eberhard

Eberhard
Wed May 30 07:17:54 CDT 2007

MrAsm schrieb:

> I showed that generated assembly code is the same to show that there
> is no run-time check or other difference between my "utter nonsense"
> and the C++ style cast.

We agree that technically, C and C++ style casts can often achieve the
same thing (RTTI/dynamic_cast now disregarded). This is "only" a matter
of good programming style, which nevertheless may be crucial for saving
frustration, time and money.

> HRESULT QueryInterface(
> REFIID iid,
> void ** ppvObject
> );
>
>
> Maybe some C++ guru would prefer using reinterpret_cast (or other form
> of C++ cast), but I like more the C style cast in this case, because I
> find it leaner, not bloated, and also I find C style cast easy to read
> in this case.

I'm not a guru, but I very much prefer reinterpret_cast here, because it
signals clearly: Double and triple check, you're on your own and the
compiler can't help you.

(Even better, the QI issue can be solved with a template, but that's
another story.)

> LVITEM lvi;
> CString strItem;
> for (int i = 0; i < m_nItems; i++)
> {
> // Insert the first item
> lvi.mask = LVIF_IMAGE | LVIF_TEXT;
> strItem.Format(_T("Item %i"), i);
> lvi.iItem = i;
> lvi.iSubItem = 0;
> lvi.pszText = (LPTSTR)(LPCTSTR)(strItem);

This is exactly the "legacy" case that I was referring to (i.e. the
"legacy" variable pszText is not declared const but used as such). I'd
prefer

lvi.pszText = const_cast< LPTSTR >( strItem.GetString() );

To me, it's much clearer what the intention is.

Re: const char assignments by LarryW

LarryW
Wed May 30 09:12:52 CDT 2007

In article <eMj0YhgoHHA.4564@TK2MSFTNGP03.phx.gbl>, Alex Blekhman wrote:
> Date: Tue, 29 May 2007 18:45:12 +0300
> From: Alex Blekhman <xfkt@oohay.moc>
> Subject: Re: const char assignments
> Newsgroups: microsoft.public.vc.language
>
> LarryW wrote:
> > How come I can do this:
> >
> > char value = '\v';
> > char c;
> > unsigned char uc;
> > signed char sc;
> >
> > c = value;
> > uc = value;
> > sc = value;
> >
> > But not this:
> >
> > const char * string = "A string";
> > const char * c_string;
> > const unsigned char * uc_string;
> > const signed char * sc_string;
> >
> > c_string = string; // this works fine
> > uc_string = string; // error: can't assign "const char *" to "const
> > unsigned char *"
> > sc_string = string; // error: can't assign "const char *" to "const
> > signed char *"
>
> Because `char' is neither signed nor unsigned. When you
> assign `char' value to signed/unsigned, then compiler
> implicitly converts it to destination type (this process is
> called "integral conversion"). However, implicit conversion
> isn't performed with pointer types (except conversion to
> `void*' type and derived to base class pointers). That's why
> you need to cast pointer types explicitly.
>
> Alex
>
I guess what puzzles me is that the compiler has no problem when these
pointers are not 'const' but complains when they are. So it's something more
than just that they're pointers.


Re: const char assignments by Alex

Alex
Wed May 30 09:40:19 CDT 2007

LarryW wrote:
>> Because `char' is neither signed nor unsigned. When you
>> assign `char' value to signed/unsigned, then compiler
>> implicitly converts it to destination type (this process is
>> called "integral conversion"). However, implicit conversion
>> isn't performed with pointer types (except conversion to
>> `void*' type and derived to base class pointers). That's why
>> you need to cast pointer types explicitly.
>>
> I guess what puzzles me is that the compiler has no problem when these
> pointers are not 'const' but complains when they are. So it's something more
> than just that they're pointers.

No, you get the same error ("Types pointed to are unrelated;
...") for non-const pointers, too:

char str[] = { "A string" };
char * string = str;
char * c_string;
unsigned char * uc_string;
signed char * sc_string;

c_string = string; // OK
uc_string = string; // error
sc_string = string; // error


Alex

Re: const char assignments by Gerry

Gerry
Wed May 30 09:55:22 CDT 2007

In article <dmjq53p4c2osqn2uhl7o5p49itf4t9m5kj@4ax.com>, mrasm@usa.com
says...
> On Wed, 30 May 2007 11:28:52 +0200, Eberhard Schefold
> <eberhard.schefold@de.bosch.com> wrote:

> I showed that generated assembly code is the same to show that there
> is no run-time check or other difference between my "utter nonsense"
> and the C++ style cast.

Nor should there be - the difference is at compile time, in which the
more specific C++ casts may in principle catch more errors.

> Maybe some C++ guru would prefer using reinterpret_cast (or other form
> of C++ cast), but I like more the C style cast in this case, because I
> find it leaner, not bloated, and also I find C style cast easy to read
> in this case.

> I just don't consider the C style cast a "utter nonsense", and I
> believe that banning C style casts is like banning 'continue' in for
> loops or having rules like "functions must have only one exit point"
> and similar things.

I tend to agree that in simple cases the C-style cast is often easier
to read; if the purpose of the cast is obvious, the C++ style tells the
reader nothing, and it is unlikely that a mistake will be made to be
caught by the compiler.

- Gerry Quinn




Re: const char assignments by LarryW

LarryW
Wed May 30 16:19:27 CDT 2007

In article <OoduzhsoHHA.596@TK2MSFTNGP06.phx.gbl>, Alex Blekhman wrote:
> Date: Wed, 30 May 2007 17:40:19 +0300
> From: Alex Blekhman <xfkt@oohay.moc>
> Subject: Re: const char assignments
> Newsgroups: microsoft.public.vc.language
>
> LarryW wrote:
> >> Because `char' is neither signed nor unsigned. When you
> >> assign `char' value to signed/unsigned, then compiler
> >> implicitly converts it to destination type (this process is
> >> called "integral conversion"). However, implicit conversion
> >> isn't performed with pointer types (except conversion to
> >> `void*' type and derived to base class pointers). That's why
> >> you need to cast pointer types explicitly.
> >>
> > I guess what puzzles me is that the compiler has no problem when these
> > pointers are not 'const' but complains when they are. So it's something more
> > than just that they're pointers.
>
> No, you get the same error ("Types pointed to are unrelated;
> ....") for non-const pointers, too:
>
> char str[] = { "A string" };
> char * string = str;
> char * c_string;
> unsigned char * uc_string;
> signed char * sc_string;
>
> c_string = string; // OK
> uc_string = string; // error
> sc_string = string; // error
>
> Alex
>
Ah, you're right, I had misread my original example. Thanks for the answers!


Re: const char assignments by Ulrich

Ulrich
Thu May 31 02:18:30 CDT 2007

[Note: dropped microsoft.public.vc.mfc ]
MrAsm wrote:
> I showed that generated assembly code is the same to show that there
> is no run-time check or other difference between my "utter nonsense"
> and the C++ style cast.

Nobody every claimed any runtime difference. ;)

The reason is programming basics:
1. Prefer compiler errors for buggy code.
2. If you can't get compile errors, prefer linker errors.
3. If you can't get those, make sure that unit tests catch errors.

IOW, you want to detect errors as early as possible. You could even split
point 1 into two points, one for the 'compiler' itself, the other for the
preprocessor.

>>Casts can be dangerous, I think we can agree to that.
>
> Yes, we agree.
>
> But sometimes they are necessary or useful.
[... COM code example snipped ...]
> // Use the LV_ITEM structure to insert the items
> LVITEM lvi;
> CString strItem;
> for (int i = 0; i < m_nItems; i++)
> {
> // Insert the first item
> lvi.mask = LVIF_IMAGE | LVIF_TEXT;
> strItem.Format(_T("Item %i"), i);
> lvi.iItem = i;
> lvi.iSubItem = 0;
> lvi.pszText = (LPTSTR)(LPCTSTR)(strItem);
>
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> CAST HERE

WTF? Replace 'CString strItem' with 'int strItem' and this crappy code will
compile, too, just to fail at runtime. Or you replace it with a 'char
strItem[20]'. Or you replace it with a 'CString* strItem = new CString;'.

If you had used

lvi.pszText = strItem.GetBuffer();

it would have worked as well. (Note: I'm not exactly sure that GetBuffer()
is the right function, I mean the one returning an LPTSTR to the contained
characters). I might even use the one returning a const one (no, not
necessarily the overloaded operator LPCTSTR) and cast it like below.

Even assuming you are using C++ string, this would have worked and would be
maintainable because both the code and the comment suitably explain what is
going on while still failing to compile if you changed strItem in an
incompatible way.

// Note: despite being a non-const pointer, the content
// is not modified.
lvi.pszText = const_cast<TCHAR*>(strItem.c_str());

> I just don't consider the C style cast a "utter nonsense",

In fact they aren't, there are rare cases where they are the only way and
correct. However, suggesting to a beginner (to me it seemed obvious the OP
was one) to use a brute-force C-style cast in order to make the compiler
compile buggy code is utter nonsense! Good code works to large extents
without any casting and almost completely without C-style casts.

> and I believe that banning C style casts is like banning 'continue' in
> for loops

It is some people's opinion that this obfuscates code, i.e. just an opinion.
In contrast I showed above that code might silently compile but break in
various horrible ways at runtime with C-style casts. Of course, that
requires that you agree with my opinion that you should detect errors at
the earliest possible time.

> or having rules like "functions must have only one exit point"

Impossible in C++ due to exceptions.

> and similar things.

"Don't play with matches!"? The same general rule IMHO applies to C-style
casts and it has exceptions, too.

Uli


Re: const char assignments by MrAsm

MrAsm
Thu May 31 03:23:17 CDT 2007

On Thu, 31 May 2007 09:18:30 +0200, Ulrich Eckhardt
<eckhardt@satorlaser.com> wrote:


>Good code works to large extents
>without any casting and almost completely without C-style casts.

That is true.


>requires that you agree with my opinion that you should detect errors at
>the earliest possible time.

I agree with you on that point.


MrAsm