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

reinterpret_cast from unsigned char* to char *

1,156 views
Skip to first unread message

Trigve

unread,
Sep 30, 2010, 1:34:47 PM9/30/10
to
Hi,
I have question regarding the reinterpret_cast from unsigned char * to
char *. As pointed in N3126 5.2.10/7:

A pointer to an object can be explicitly converted to a pointer to a
different object type.(70) When a
prvalue v of type "pointer to T1" is converted to the type "pointer to
cv T2", the result is static_cast<cv
T2*>(static_cast<cv void*>(v)) if both T1 and T2 are standard-layout
types (3.9) and the alignment
requirements of T2 are no stricter than those of T1. Converting a
prvalue of type "pointer to T1" to the
type "pointer to T2" (where T1 and T2 are object types and where the
alignment requirements of T2 are no
stricter than those of T1) and back to its original type yields the
original pointer value. The result of any
other such pointer conversion is unspecified.

reinterpret_cast<char *>(pointer_to_unsigned_char) will be "rewritten"
like
static_cast<char *>(static_cast<void *>(pointer_to_unsigned_char)). Is
result of the last statement of static_casts defined in standard? Can
I use char * result? I've found 5.2.9/13 but this doesn't define the
result (?) of my static_casts.

Could someone explain wherever the reinterpret_cast from unsigned
char* to char * is defined by standard or not, please?

Thanks

Trigve

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Joshua Maurice

unread,
Oct 2, 2010, 4:38:13 AM10/2/10
to

If you're looking for explicit wording, it's not there. I think
several of the regulars and I had a fun thread a while back on
comp.lang.c++ where we talked about this, and we couldn't decide
definitively one way or the other. I can't seem to find that thread at
the moment. Sorry.

The relevant portions appear to be:

C++03 3.8 Object lifetime / 5 and 6, which explicitly mention some
sort of exception for casting uninitialized memory or memory from a
destroyed object to char or unsigned char.

C++03 3.9 Types / 2 and 3, which guarantees that std::memcpy on POD
complete objects works as expected.

C++03 3.9.1 Fundamental types / 1, which guarantees that all bits in
char and unsigned char objects participate in the value of the object.
I believe this means no trap signs, parity bits, or anything else
"weird", which might allow you to read and write to POD complete
objects through a char or unsigned char lvalue.

The infamous C++03 3.10 Lvalues and rvalues / 15, aka the strict
aliasing rule, seems to allow reading and writing to objects through
char and unsigned char lvalues.

The standard does strongly imply that you can read and write to any
complete object of POD type through a char or unsigned char lvalue
(aka through a char pointer or unsigned char pointer). However, the
only explicit guarantee which I can find about reading and writing to
a POD is through std::memcpy. Moreover, there are important
restrictions placed on this. While char and unsigned char do not have
trap values, other POD types may, so you can write a trap value to a
POD type, which might later crash the system when you try to read from
it or write to it through that POD type lvalue. Only even think about
doing this on objects where the most derived object is of POD type.
Even then, it's probably quite dangerous to do this on POD sub-
objects, such as base class sub-objects or member sub-objects.
Finally, there are subtle fun guarantees about what you're exactly
allowed to read and write to uninitialized memory when that memory
used to have a non-trivial destructor. (C++03 3.8 Object lifetime / 5
and 6.) I'm not even going to pretend to summarize them here.

So, to answer your question: if you have a complete object which is
char array or a single char object, and you read from or write to that
char array or char object through an unsigned char lvalue, then it
should work. By "should", I mean it's relatively clear this is the
intent of the standard, and IIRC all compilers will also do "the right
thing" (tm).

So, how do you get a unsigned char lvalue which "points to" a char
object? Option 1: take the char*, static_cast to void*, then to
unsigned char*. Option 2: just do one step with reinterpret_cast. So,
this is a little beyond my league of expertise, but I strongly suspect
that
static_cast<T*>(static_cast<void*>(some_pointer))
is entirely equivalent to
reinterpret_cast<T*>(some_pointer)
on any sane implementation. I don't think this is required by the
standard; but I think it would have to be a malicious implementation
otherwise, and I don't care much about malicious implementations.

The entire casting thing is a mess and quite underspecified. There are
even worse things in there, like C++03 3.8 Object lifetime / 1, which
states that the lifetime of a POD object starts when memory with
proper alignment is obtained. That means a single piece of memory
contains infinitely many POD objects, which stands in stark contrast
to the intent of the strict aliasing rules of C++03 3.10 Lvalues and
rvalues / 15. So, cast at your own risk, and in a production system
you should check the assembly on each platform you care about when you
do any sort of "funky" casting.

I wonder if C++0x has cleaned any of this up. I doubt it, but I hope
so.

Trigve

unread,
Oct 2, 2010, 9:53:39 AM10/2/10
to
On 2. Okt, 10:38 h., Joshua Maurice <joshuamaur...@gmail.com> wrote:
> If you're looking for explicit wording, it's not there. I think
> several of the regulars and I had a fun thread a while back on
> comp.lang.c++ where we talked about this, and we couldn't decide
> ...
Before I've posted to c.l.c++.m I've done some reasearch and found
that I cannot get clean answer. See
http://groups.google.com/group/comp.std.c++/browse_thread/thread/ee50864e7ed29021/ea62d566b43fd3b9?lnk=gst&q=reinterpret_cast+unsign
ed+char+*+to+char+*#ea62d566b43fd3b9
and
http://groups.google.com/group/comp.lang.c++.moderated/browse_thread/thread/ad5873ce25d49324/3d1c06f3f25f2b6c?lnk=gst&q=reinterpret_
cast+unsigned+char+*+to+char+*#3d1c06f3f25f2b6c

[...]
> ... that


> static_cast<T*>(static_cast<void*>(some_pointer))
> is entirely equivalent to
> reinterpret_cast<T*>(some_pointer)

> on any sane implementation. I don't think this is required by the ..
As I mentioned earlier in the current draft there is something like
this "..the result is static_cast<cv T2*>(static_cast<cv void*>(v)) if


both T1 and T2 are standard-layout types (3.9) and the alignment

requirements of T2 are no stricter than those of T1..".

[...]


> I wonder if C++0x has cleaned any of this up. I doubt it, but I hope
> so.

Therefore I'm posting here again if something has changed because
there were some changes to reinterpret_cast<> and static_cast<> AFAIK
in new standard.

Thanks

Trigve

Daniel Krügler

unread,
Oct 3, 2010, 3:01:19 AM10/3/10
to
On 30 Sep., 19:34, Trigve <trig...@gmail.com> wrote:
> Hi,
> I have question regarding the reinterpret_cast from unsigned char * to
> char *. As pointed in N3126 5.2.10/7:
>
> A pointer to an object can be explicitly converted to a pointer to a
> different object type.(70) When a
> prvalue v of type "pointer to T1" is converted to the type "pointer to
> cv T2", the result is static_cast<cv
> T2*>(static_cast<cv void*>(v)) if both T1 and T2 are standard-layout
> types (3.9) and the alignment
> requirements of T2 are no stricter than those of T1. Converting a
> prvalue of type "pointer to T1" to the
> type "pointer to T2" (where T1 and T2 are object types and where the
> alignment requirements of T2 are no
> stricter than those of T1) and back to its original type yields the
> original pointer value. The result of any
> other such pointer conversion is unspecified.
>
> reinterpret_cast<char *>(pointer_to_unsigned_char) will be "rewritten"
> like
> static_cast<char *>(static_cast<void *>(pointer_to_unsigned_char)). Is
> result of the last statement of static_casts defined in standard? Can
> I use char * result? I've found 5.2.9/13 but this doesn't define the
> result (?) of my static_casts.

I believe the combining effect of

http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#573
http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#597
http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#944
http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1120

will make that work.

HTH & Greetings from Bremen,

Daniel Krügler

Trigve

unread,
Oct 3, 2010, 11:03:14 AM10/3/10
to
On 3. Okt, 09:01 h., Daniel Krügler <daniel.krueg...@googlemail.com>
wrote:

>
> I believe the combining effect of
>
>
http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#573http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#597http:/

Thanks for reply.

If I understand it correctly it does also apply for conversion between
stricter alignment type to less stricter i.e. from int * -> char *? Am
I right?

Daniel Krügler

unread,
Oct 4, 2010, 1:23:45 AM10/4/10
to
On 3 Okt., 17:03, Trigve <trig...@gmail.com> wrote:
> If I understand it correctly it does also apply for conversion between
> stricter alignment type to less stricter i.e. from int * -> char *? Am
> I right?

It's impossible to deduce that from the current state
of this issue.

Trigve

unread,
Oct 4, 2010, 5:18:47 PM10/4/10
to
On 4. Okt, 07:23 h., Daniel Krügler <daniel.krueg...@googlemail.com>
wrote:
>

> It's impossible to deduce that from the current state
> of this issue.
>
> Greetings from Bremen,
>
> Daniel Krügler
>

I have to add that I'm interested in C++0x standard only. Sorry for
not mentioning it before.

According to 3.9/2 this code has defined behaviour:

int s = 5;
char *bufer = new char[sizeof(int)];
std::memcpy(buffer, &s, sizeof(s));

Shouldn't the code above be semantically same as:

int *p = &s;
char *c = reinterpret_cast<char *>(p);

I think that if 3.10/5-4 could be applied not only in this specific
context, then if "char *c = static_cast<char *>(static_cast<void
*>(&some_type));" will be semantically the same as
"std::memcpy(buffer, &some_type, sizeof(some_type));" (where buffer is
some char buffer large enough) where some_type is trivially copyable
type and alignment of some_type are no stricter (which should be
always true) then according to 3.10/10 we could access stored value
through "c". And then according to 5.2.10/7 it will be defined
behaviour. This code could be well defined, or wouldn't it?:

int a = 5;
int b;
std::memcpy(&b, reinterpret_cast<char *>(&a), sizeof(a));

I'm asking because I want to now if I can make something like this
(without UB):

std::ifstrem input(...); // Opened as binary
....
int vaue;
input.read(reinterpret_cast<char *>(&value), sizeof(value)); // Where
input "has" int

Thanks

Trigve

0 new messages