www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Casting Pointers?

reply John Burton <john.burton jbmail.com> writes:
I've been unable to find a clear definitive answer to this so 
please point me to one if it already exists in the manual or the 
forums.

Is it safe to cast pointer types?

     double data;
     long p = *cast(long*)&data;

(Excuse any silly syntax errors as I'm doing this on my phone).

This used to be possible in C until people recently decided it 
not only was wrong, it had always been wrong :P (Ok I'm not 
entirely serious there but that's what this issue feels like...)

Is this legal / valid in D and if not what is the appropriate way 
to efficiently access data like this?
May 12 2016
next sibling parent ZombineDev <petar.p.kirov gmail.com> writes:
On Thursday, 12 May 2016 at 08:41:25 UTC, John Burton wrote:
 I've been unable to find a clear definitive answer to this so 
 please point me to one if it already exists in the manual or 
 the forums.

 Is it safe to cast pointer types?

     double data;
     long p = *cast(long*)&data;

 (Excuse any silly syntax errors as I'm doing this on my phone).

 This used to be possible in C until people recently decided it 
 not only was wrong, it had always been wrong :P (Ok I'm not 
 entirely serious there but that's what this issue feels like...)

 Is this legal / valid in D and if not what is the appropriate 
 way to efficiently access data like this?
Yes, it's perfectly legal in system code, but only if you know what you're doing ;) Take a look at std.math for example: https://github.com/dlang/phobos/blob/v2.071.0/std/math.d#L4839
May 12 2016
prev sibling next sibling parent reply Stefan Koch <uplink.coder googlemail.com> writes:
On Thursday, 12 May 2016 at 08:41:25 UTC, John Burton wrote:
 I've been unable to find a clear definitive answer to this so 
 please point me to one if it already exists in the manual or 
 the forums.

 Is it safe to cast pointer types?

     double data;
     long p = *cast(long*)&data;

 (Excuse any silly syntax errors as I'm doing this on my phone).

 This used to be possible in C until people recently decided it 
 not only was wrong, it had always been wrong :P (Ok I'm not 
 entirely serious there but that's what this issue feels like...)

 Is this legal / valid in D and if not what is the appropriate 
 way to efficiently access data like this?
How would such a cast be safe?
May 12 2016
next sibling parent Rene Zwanenburg <renezwanenburg gmail.com> writes:
On Thursday, 12 May 2016 at 09:25:49 UTC, Stefan Koch wrote:
 How would such a cast be safe?
I'm guessing safe as in defined behavior.
May 12 2016
prev sibling parent John Burton <john.burton jbmail.com> writes:
On Thursday, 12 May 2016 at 09:25:49 UTC, Stefan Koch wrote:
 On Thursday, 12 May 2016 at 08:41:25 UTC, John Burton wrote:
 I've been unable to find a clear definitive answer to this so 
 please point me to one if it already exists in the manual or 
 the forums.

 Is it safe to cast pointer types?

     double data;
     long p = *cast(long*)&data;

 (Excuse any silly syntax errors as I'm doing this on my phone).

 This used to be possible in C until people recently decided it 
 not only was wrong, it had always been wrong :P (Ok I'm not 
 entirely serious there but that's what this issue feels 
 like...)

 Is this legal / valid in D and if not what is the appropriate 
 way to efficiently access data like this?
How would such a cast be safe?
"Safe" as in it produces a valid long value by interpreting the bytes of the stored double. Obviously if it works it's very system dependent. But in C it's simply undefined behavior to read a value stored using one pointer type using a pointer to a different type. (With some additional rules about char in a few cases). The whole strict aliasing businesss
May 12 2016
prev sibling next sibling parent reply Rene Zwanenburg <renezwanenburg gmail.com> writes:
On Thursday, 12 May 2016 at 08:41:25 UTC, John Burton wrote:
 Is this legal / valid in D and if not what is the appropriate 
 way to efficiently access data like this?
Phobos / druntime use casts like this as well, but there has been some discussion as to whether it should be guaranteed to be correct. There are good reasons the C folks disallow it (well, performance of course, what else? ^^), and the reasoning applies to D as well. In this case, you can use a union: union DL { double d; long l; } auto dl = DL(1.0); writeln(dl.l);
May 12 2016
parent reply Marco Leise <Marco.Leise gmx.de> writes:
Am Thu, 12 May 2016 09:32:17 +0000
schrieb Rene Zwanenburg <renezwanenburg gmail.com>:

 In this case, you can use a union:
 
 union DL
 {
 	double d;
 	long l;
 }
 
 auto dl = DL(1.0);
 writeln(dl.l);
The pointer cast solution is specifically supported at CTFE, because /unions/ don't work there. :p -- Marco
May 12 2016
parent Rene Zwanenburg <renezwanenburg gmail.com> writes:
On Thursday, 12 May 2016 at 22:23:38 UTC, Marco Leise wrote:
 The pointer cast solution is specifically supported at CTFE, 
 because /unions/ don't work there. :p
Well that's a problem ^^ I remember a discussion quite a while ago where Walter stated D should have strict aliasing rules, let me see if I can find it.. Ah here: http://forum.dlang.org/post/jg3f21$1jqa$1 digitalmars.com On Saturday, 27 July 2013 at 06:58:04 UTC, Walter Bright wrote:
 Although it isn't in the spec, D should be "strict aliasing". 
 This is because:

 1. it enables better code generation

 2. there are ways, such as unions, to get the other aliasing 
 that doesn't break strict aliasing
On Saturday, 27 July 2013 at 08:59:54 UTC, Walter Bright wrote:
 On 7/27/2013 1:57 AM, David Nadlinger wrote:
 We need to carefully formalize this then, and quickly.

 [...]
I agree. Want to do an enhancement request on bugzilla for it?
May 13 2016
prev sibling next sibling parent reply Dicebot <public dicebot.lv> writes:
On Thursday, 12 May 2016 at 08:41:25 UTC, John Burton wrote:
 Is this legal / valid in D and if not what is the appropriate 
 way to efficiently access data like this?
We rely on this cast to be legal and well-defined in a lot of Sociomantic code, banning would be a real disaster :X
May 12 2016
parent reply Dicebot <public dicebot.lv> writes:
On Thursday, 12 May 2016 at 09:33:54 UTC, Dicebot wrote:
 On Thursday, 12 May 2016 at 08:41:25 UTC, John Burton wrote:
 Is this legal / valid in D and if not what is the appropriate 
 way to efficiently access data like this?
We rely on this cast to be legal and well-defined in a lot of Sociomantic code, banning would be a real disaster :X
(most common case is casting between `char[]` and `struct S { char[]; }`)
May 12 2016
next sibling parent reply "H. S. Teoh via Digitalmars-d" <digitalmars-d puremagic.com> writes:
On Thu, May 12, 2016 at 09:38:27AM +0000, Dicebot via Digitalmars-d wrote:
 On Thursday, 12 May 2016 at 09:33:54 UTC, Dicebot wrote:
[...]
We rely on this cast to be legal and well-defined in a lot of
Sociomantic code, banning would be a real disaster :X
(most common case is casting between `char[]` and `struct S { char[]; }`)
Does alias this solve the problem, or it introduces new ones? T -- Let's eat some disquits while we format the biskettes.
May 12 2016
parent Dicebot <public dicebot.lv> writes:
On Thursday, 12 May 2016 at 14:20:28 UTC, H. S. Teoh wrote:
 Does alias this solve the problem, or it introduces new ones?
void foo ( ref char[] x ) { static assert (x.sizeof == Wrapper.sizeof); (cast(Wrapper*) &x).someMethod(); // may resize x } Not sure how alias this can be applicable here. One recurring reason to write code like this is when one replaces plain type with more type-safe wrapper but wants to keep old API working with raw arrays as deprecated.
May 12 2016
prev sibling parent Johannes Pfau <nospam example.com> writes:
Am Thu, 12 May 2016 09:38:27 +0000
schrieb Dicebot <public dicebot.lv>:

 On Thursday, 12 May 2016 at 09:33:54 UTC, Dicebot wrote:
 On Thursday, 12 May 2016 at 08:41:25 UTC, John Burton wrote:  
 Is this legal / valid in D and if not what is the appropriate 
 way to efficiently access data like this?  
We rely on this cast to be legal and well-defined in a lot of Sociomantic code, banning would be a real disaster :X
(most common case is casting between `char[]` and `struct S { char[]; }`)
That cast is safe even with strict aliasing rules: http://stackoverflow.com/questions/9747010/does-accessing-the-first-field-of-a-struct-via-a-c-cast-violate-strict-aliasing So it's highly unlikely this will ever become undefined behavior in D :-) In the end a compiler writers can make up arbitrary aliasing rules: For example in D ubyte[] should probably alias all [] slices, ubyte* aliases all pointers (like char* in C), ... double and long are fundamentally different though, so aliasing wouldn't be allowed for these types in most languages. AFAIK no D compiler actually enforces strict aliasing right now. GDC explicitly disables all aliasing related optimizations.
May 12 2016
prev sibling next sibling parent "H. S. Teoh via Digitalmars-d" <digitalmars-d puremagic.com> writes:
On Thu, May 12, 2016 at 08:41:25AM +0000, John Burton via Digitalmars-d wrote:
 I've been unable to find a clear definitive answer to this so please
 point me to one if it already exists in the manual or the forums.
 
 Is it safe to cast pointer types?
 
     double data;
     long p = *cast(long*)&data;
 
 (Excuse any silly syntax errors as I'm doing this on my phone).
 
 This used to be possible in C until people recently decided it not only was
 wrong, it had always been wrong :P (Ok I'm not entirely serious there but
 that's what this issue feels like...)
 
 Is this legal / valid in D and if not what is the appropriate way to
 efficiently access data like this?
AFAIK this is legal in D, though it does break safe-ty so it can only be used in system code. An alternative is to use a union: long reinterpretAsLong(double data) safe { union U { double d; long l; } U u; u.d = data; return u.l; } A bit verbose, but disassembly shows that the dmd -O is able to reduce it to a single mov instruction, as it should be. T -- English is useful because it is a mess. Since English is a mess, it maps well onto the problem space, which is also a mess, which we call reality. Similarly, Perl was designed to be a mess, though in the nicest of all possible ways. -- Larry Wall
May 12 2016
prev sibling parent Anon <anon anon.anon> writes:
On Thursday, 12 May 2016 at 08:41:25 UTC, John Burton wrote:
 I've been unable to find a clear definitive answer to this so 
 please point me to one if it already exists in the manual or 
 the forums.

 Is it safe to cast pointer types?

     double data;
     long p = *cast(long*)&data;

 (Excuse any silly syntax errors as I'm doing this on my phone).

 This used to be possible in C until people recently decided it 
 not only was wrong, it had always been wrong :P (Ok I'm not 
 entirely serious there but that's what this issue feels like...)
This is a Bad Idea in C because types in C aren't actually well-defined. `long` is required to be at least 32 bits. `double` is required to be a floating point type. They will often not match up in sizes the way you might think. The spec doesn't even require `double` to be IEEE (that's an optional annex). Clang on Linux x86_64 has both `long` and `double` as 64-bit types. Clang on Linux x86 has `long` as 32-bit, `double` as 64-bit.
 Is this legal / valid in D and if not what is the appropriate 
 way to efficiently access data like this?
In D, both `long` and `double` are defined in the spec to be 64-bits, regardless of compiler/os/arch. It isn't "safe" (because casting pointers is never safe), but it should behave predictably. Note that D does have its own poorly-defined types, such as `real`, that you will need to be careful with.
May 12 2016