473,383 Members | 1,864 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,383 software developers and data experts.

Just how powerful is the cast?


Let's assume that we're working on the following system:

CHAR_BIT == 8
sizeof( char* ) == 4 (i.e. 32-Bit)
Furthermore, lets assume that the memory addresses are distributed as
follows:

0x00000000 through 0xFFFFFFFE : Valid byte addresses
0xFFFFFFFF : Null pointer value

If we want to set a pointer to null, we can just do the following:

char *p = 0; /* Now contains 0xFFFFFFFF */

If, for some wacky reason, we wanted to set it to all bits zero, then we
could do:

memset(p, 0, sizeof p); /* Now contains 0x00000000 */

I'd like to know what happens however when we explicitly use a cast:

p = reinterpret_cast<char*>(0);

p = (char*)0;

Do the above two lines of code set our pointer to the legitimate null
pointer value, or do they set it to all bits zero? (My guess is that it's
the null pointer value)

Or consider the following:

#include <iostream>

int main()
{
unsigned i;

std::cin >> i;

/* Let's assume that user types in 0 */

char *p = reinterpret_cast<char*>( i );
}

I would presume that the above code snippet sets p to all bits zero in
the above, rather than the legitimate null pointer value.

I'm very familiar with the concept of "type mismatch"; for instance, I
realise that the following is broken:

double *p;
float k = 34.2;

p = k;

The literal, 0, is of the type "signed int". I've always thought it
strange that the following triggers a type-mismatch error:

char *p = 5;

While the following doesn't:

char *p = 0;
From the knowledge I have at the moment, it seems to me that an
expression known at compile-time to be equal to zero gets special
treatment -- even when cast explicitly. This would lead me to believe
that the following line sets p to the null pointer value:

char *p = reinterpret_cast<char*>( 7 - 5 - 2 );

, althought my example which contained user input would set the pointer
to all bits zero rather than the legitimate null pointer value.

Jun 22 '06 #1
9 2683

"Frederick Gotham" <fg*******@SPAM.com> skrev i meddelandet
news:Xn***************************@195.188.240.200 ...

Let's assume that we're working on the following system:

CHAR_BIT == 8
sizeof( char* ) == 4 (i.e. 32-Bit)
Furthermore, lets assume that the memory addresses are distributed
as
follows:

0x00000000 through 0xFFFFFFFE : Valid byte addresses
0xFFFFFFFF : Null pointer value

If we want to set a pointer to null, we can just do the following:

char *p = 0; /* Now contains 0xFFFFFFFF */

If, for some wacky reason, we wanted to set it to all bits zero,
then we
could do:

memset(p, 0, sizeof p); /* Now contains 0x00000000 */
Assuming that char(0) is all zero bits, yes. Who knows on this whacky
system?


I'd like to know what happens however when we explicitly use a cast:

p = reinterpret_cast<char*>(0);

p = (char*)0;

Do the above two lines of code set our pointer to the legitimate
null
pointer value, or do they set it to all bits zero? (My guess is that
it's
the null pointer value)
When p is a char*, the expressions

p = (char*)0;
and
p = 0;

are identical.

The reinterpret_cast is a bit fishy, because it is allowed to have
some implementation defined mappings. I believe we would have to
consult the (whacky) compiler manual.

Or consider the following:

#include <iostream>

int main()
{
unsigned i;

std::cin >> i;

/* Let's assume that user types in 0 */

char *p = reinterpret_cast<char*>( i );
}

I would presume that the above code snippet sets p to all bits zero
in
the above, rather than the legitimate null pointer value.
I wouldn't presume too much. :-)
I'm very familiar with the concept of "type mismatch"; for instance,
I
realise that the following is broken:

double *p;
float k = 34.2;

p = k;

The literal, 0, is of the type "signed int". I've always thought it
strange that the following triggers a type-mismatch error:

char *p = 5;

While the following doesn't:

char *p = 0;
That's just the way it is. Zero is special!

From the knowledge I have at the moment, it seems to me that an
expression known at compile-time to be equal to zero gets special
treatment -- even when cast explicitly. This would lead me to
believe
that the following line sets p to the null pointer value:

char *p = reinterpret_cast<char*>( 7 - 5 - 2 );
If you skip the reinterpret_cast, you are right

char* p = 7 - 5 - 2;

creates a null pointer. With the cast, I don't know for sure.

, althought my example which contained user input would set the
pointer
to all bits zero rather than the legitimate null pointer value.


The user would surely input -5 instead, and break the code entirely.
:-)
Bo Persson
Jun 22 '06 #2
"Bo Persson" <bo*@gmb.dk> wrote:
"Frederick Gotham" skrev i meddelandet
...
If, for some wacky reason, we wanted to set it to all bits zero,
then we
could do:

memset(p, 0, sizeof p); /* Now contains 0x00000000 */


Assuming that char(0) is all zero bits, yes. Who knows on this whacky
system?


No need to assume. That is 0, not '0';
Jun 22 '06 #3

"Roberto Waltman" <us****@rwaltman.net> skrev i meddelandet
news:tg********************************@4ax.com...
"Bo Persson" <bo*@gmb.dk> wrote:
"Frederick Gotham" skrev i meddelandet
...
If, for some wacky reason, we wanted to set it to all bits zero,
then we
could do:

memset(p, 0, sizeof p); /* Now contains 0x00000000 */


Assuming that char(0) is all zero bits, yes. Who knows on this
whacky
system?


No need to assume. That is 0, not '0';


But memset takes an int parameter, that it has to convert to type
char. On normal hardware this is easy, but on a hypothetical hardware
using 0xFFFFFFFF for the null pointer, who knows what bit pattern is
used for char(0)?!

Just trying to be picky! :-)
Bo Persson
Jun 22 '06 #4
Frederick Gotham wrote:
...
Furthermore, lets assume that the memory addresses are distributed as
follows:

0x00000000 through 0xFFFFFFFE : Valid byte addresses
0xFFFFFFFF : Null pointer value

If we want to set a pointer to null, we can just do the following:

char *p = 0; /* Now contains 0xFFFFFFFF */

If, for some wacky reason, we wanted to set it to all bits zero, then we
could do:

memset(p, 0, sizeof p); /* Now contains 0x00000000 */

I'd like to know what happens however when we explicitly use a cast:

p = reinterpret_cast<char*>(0);

p = (char*)0;

Do the above two lines of code set our pointer to the legitimate null
pointer value, or do they set it to all bits zero? (My guess is that it's
the null pointer value)
Yes. Both produce the null pointer value. Note though that the second
one in this case is interpreted as 'static_cast', not as 'reinterpret_cast'.
Or consider the following:

#include <iostream>

int main()
{
unsigned i;

std::cin >> i;

/* Let's assume that user types in 0 */

char *p = reinterpret_cast<char*>( i );
}

I would presume that the above code snippet sets p to all bits zero in
the above, rather than the legitimate null pointer value.
You are right when you assume that the code is not guaranteed to produce
the null pointer value. However, the 'int -> char*' mapping produced by
'reinterpret_cast' in this case is implementation defined, which means
that in general case there's no guarantee that 'p' is all bits zero as well.

The literal, 0, is of the type "signed int". I've always thought it
strange that the following triggers a type-mismatch error:

char *p = 5;

While the following doesn't:

char *p = 0;
From the knowledge I have at the moment, it seems to me that an
expression known at compile-time to be equal to zero gets special
treatment -- even when cast explicitly.
Yes, that's exactly correct. See the definition of 'null pointer
constant' in the language specification.
This would lead me to believe
that the following line sets p to the null pointer value:

char *p = reinterpret_cast<char*>( 7 - 5 - 2 );


That's true. The same can be said about, for example,

char *p =
reinterpret_cast<char*>(sizeof(7)*2 - sizeof(5) - sizeof(int));

or

char *p = reinterpret_cast<char*>(false);

--
Best regards,
Andrey Tarasevich
Jun 22 '06 #5
Bo Persson schrieb:
0x00000000 through 0xFFFFFFFE : Valid byte addresses
0xFFFFFFFF : Null pointer value

If we want to set a pointer to null, we can just do the following:

char *p = 0; /* Now contains 0xFFFFFFFF */

If, for some wacky reason, we wanted to set it to all bits zero,
then we
could do:

memset(p, 0, sizeof p); /* Now contains 0x00000000 */


Assuming that char(0) is all zero bits, yes. Who knows on this whacky
system?


Assuming p still is = 0, this is undefined behaviour. Dereferencing a
null-pointer, isn't it?

Thomas
Jun 22 '06 #6
Bo Persson posted:

But memset takes an int parameter, that it has to convert to type
char. On normal hardware this is easy, but on a hypothetical hardware
using 0xFFFFFFFF for the null pointer, who knows what bit pattern is
used for char(0)?!

The Standard says exactly how unsigned integers store their values (i.e.
i.e. something like "obey modulo X arithemtic").

It also says that the signed variety integer type has the same bit pattern
for the values which can be expressed accurately with the unsigned variety.

Therefore, the unsigned char variety of zero is all bits zero.

And hence, the signed char variety of zero is all bits zero.
Jun 22 '06 #7
Frederick Gotham wrote:
I'd like to know what happens however when we explicitly use a cast:

p = reinterpret_cast<char*>(0);

p = (char*)0;
But note that the cast in the second line here is special. It creates a
null pointer constant of type char *. The zero is an integral constant
expression having value zero, and as such it is a null pointer
constant. It can be converted to a null pointer value of a specific
pointer type by means of a static_cast or equivalent. Note that I said
value, not null pointer constant. The expression 0 is a null pointer
constant. The expression (char *) 0 is a null pointer value of type
char *.

On the other hand, the result of the reinterpret_cast is similar to
this:

int non_constant_zero = 0;
p = (char *) non_constant_zero;

I.e. implementation-defined conversion. It could well be that it will
just convert the 0 to an all-zero bit pattern. This would be the the
most sensible way to do it.

The reason for this is that the C++ standard does not require
reinterpret_cast to treat null pointer constants specially, and fall
back on the portable conversion.
Do the above two lines of code set our pointer to the legitimate null
pointer value, or do they set it to all bits zero? (My guess is that it's
the null pointer value)

Or consider the following:

#include <iostream>

int main()
{
unsigned i;

std::cin >> i;

/* Let's assume that user types in 0 */

char *p = reinterpret_cast<char*>( i );
Here, you can also write

char *p = (char *) i;

This is semantically equivalent to reinterpret_cast. The C style cast
in C++ is just an interface to the C++-style casts.

The only one of the C++ style casts (const_cast, static_cast,
dynamic_cast, reinterpret_cast) which can do an int to char *
conversion is reinterpret_cast. So that is the one that is will be
chosen to implement the C style cast notation.
The literal, 0, is of the type "signed int". I've always thought it
strange that the following triggers a type-mismatch error:

char *p = 5;

While the following doesn't:

char *p = 0;
This idea is inherited from the ANSI C language. An integral constant
expression that has value zero plays a special semantic role in the
language. It serves as a null pointer constant. In ANSI C, in fact,
even such a constant cast to (void *) is still a null pointer constant,
and not a null pointer value of type void *. So for instance, this is
valid:

void (*f)(int) = (void *) 0;

whereas non-constant (void *) values cannot be converted to function
pointers. The entire "(void *) 0" is a special expression that just
means "null pointer constant". (In the C language, I repeat! In C++
(void *) 0 is a null pointer value of type void *, and not a null
pointer constant.
From the knowledge I have at the moment, it seems to me that an
expression known at compile-time to be equal to zero gets special
treatment -- even when cast explicitly.
That is correct. When cast explicitly, its special semantic role is
taken into account, depending on the cast operator! reinterpret_cast
doesn't care; it treats the null pointer constant as an integer zero.

This would lead me to believe that the following line sets p to the null pointer value:

char *p = reinterpret_cast<char*>( 7 - 5 - 2 );


But here, you specifically request the non-portable conversion of
reinterpret_cast, so its special semantics apply. Under that semantics,
the zero is really just an ordinary zero. The reinterpret_cast does not
handle zero constants specially, and it does not have "fall back"
behavior onto portable conversions.

A null pointer constant can be converted to char * by a weaker
conversion. So if you write

char *p = (char *) (7 - 5 - 2);

This C-style cast is /not/ the same as a reinterpret_cast. A
static_cast will do this job, so that's what it's equivalent to:

char *p = static_cast<char *>(7 - 5 - 2);

And because a cast is not needed at all to convert 7 - 5 - 2 to char
*, this static_cast doesn't do anything special. It does the same
conversion that happens when some variable of type char * is
initialized with a null pointer constant, e.g:

typedef char *T;
T temp(7-5-2); // no cast needed

Note finally that a reinterpret_cast /is/ required to convert null
pointer /values/ from one type to null pointer values of another. So
this should in fact give you a null pointer:

char *p = reinterpret_cast<char *>((void *) (7 - 5 - 2));

The reuqirement comes from paragraph 8 of section 5.2.10. :)

Jun 23 '06 #8
Kaz Kylheku wrote:
Frederick Gotham wrote:
I'd like to know what happens however when we explicitly use a cast:

p = reinterpret_cast<char*>(0);

p = (char*)0;

...
On the other hand, the result of the reinterpret_cast is similar to
this:

int non_constant_zero = 0;
p = (char *) non_constant_zero;

I.e. implementation-defined conversion. It could well be that it will
just convert the 0 to an all-zero bit pattern. This would be the the
most sensible way to do it.

The reason for this is that the C++ standard does not require
reinterpret_cast to treat null pointer constants specially, and fall
back on the portable conversion.


One the one hand, in the original version of the standard the normative
text does not require that null pointer constant is treated by
'reinterpret_cast' differently from other integral values. On the other
hand, the footnote 64 states that null pointer constants have to yield
null pointer values after being converted by 'reinterpret_cast'. It is
true that footnotes are not normative, but at least it demonstrates the
original intent of the committee. And the original intent was that
'reinterpret_cast<char*>(0)' does yield the null pointer value.

However, this will probably be changed in the future revisions of the
standard to the implementetion-defined behavior you describe (see
http://open-std.org/jtc1/sc22/wg21/d...fects.html#463)

--
Best regards,
Andrey Tarasevich
Jun 23 '06 #9
Frederick Gotham wrote:
Bo Persson posted:

But memset takes an int parameter, that it has to convert to type
char. On normal hardware this is easy, but on a hypothetical hardware
using 0xFFFFFFFF for the null pointer, who knows what bit pattern is
used for char(0)?!

The Standard says exactly how unsigned integers store their values (i.e.
i.e. something like "obey modulo X arithemtic").

It also says that the signed variety integer type has the same bit pattern
for the values which can be expressed accurately with the unsigned
variety.

Therefore, the unsigned char variety of zero is all bits zero.

And hence, the signed char variety of zero is all bits zero.


Well, there could be different values for +0 and -0, so you have be careful
not to get a negative zero ;-)

Jun 23 '06 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

7
by: Dan V. | last post by:
Still struggling with css. Anyone know how to put a tope background colour (matches the right part of the banner image) that stretches to the max. size of the window like the main div? My header...
5
by: Nick Flandry | last post by:
I'm running into an Invalid Cast Exception on an ASP.NET application that runs fine in my development environment (Win2K server running IIS 5) and a test environment (also Win2K server running IIS...
4
by: PontiMax | last post by:
Hi. Not sure whether this is the right group but I am looking for some powerful asp.net grid control. The grid should be editable, allow some header adjustments (e.g. multi-part row and column...
16
by: the.duckman | last post by:
G'Day. Anybodey got an idea on this problem. Say I have a function object doCast(object obj, Type t); It's job is to cast the obect (obj) to a new type (t) and return it. Sounds so...
4
by: nutty | last post by:
Hi, In my code I use two implicit casts in a row. VC compiled it in all version I have. 7.1 and 8.0, but it seems not to be standard. Comeau in strict mode and gcc don't accept it. Of course,...
5
by: Frederick Gotham | last post by:
Before I begin, here's a list of assumptions for this particular example: (1) unsigned int has no padding bits, and therefore no invalid bit- patterns or trap representations. (2) All types have...
7
by: Sky | last post by:
I have been looking for a more powerful version of GetType(string) that will find the Type no matter what, and will work even if only supplied "{TypeName}", not the full "{TypeName},{AssemblyName}"...
18
by: bsruth | last post by:
I tried for an hour to find some reference to concrete information on why this particular inheritance implementation is a bad idea, but couldn't. So I'm sorry if this has been answered before....
66
by: mensanator | last post by:
Probably just me. I've only been using Access and SQL Server for 12 years, so I'm sure my opinions don't count for anything. I was, nevertheless, looking forward to Sqlite3. And now that gmpy...
1
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
0
by: ryjfgjl | last post by:
In our work, we often need to import Excel data into databases (such as MySQL, SQL Server, Oracle) for data analysis and processing. Usually, we use database tools like Navicat or the Excel import...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.