www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - reinterpret_cast or something...

reply nod <nod_member pathlink.com> writes:
Is there a good reason why the following should not be allowed:

---
char[] buf;
// ...read into buf...

uint32_t fourcc = cast(uint32_t) buf[0..4];
---

The values are the same size, and the code clearly shows my intention to
reinterpret the byte data as an integer value. I could cast to pointers and
back, but that's kind of roundabout and then I lose automatic bounds checking.

Ah well.. There's probably an easy way I haven't thought of yet. Do enlighten
me.
Mar 20 2005
next sibling parent reply "Ben Hinkle" <ben.hinkle gmail.com> writes:
"nod" <nod_member pathlink.com> wrote in message 
news:d1kn6g$19a3$1 digitaldaemon.com...
 Is there a good reason why the following should not be allowed:

 ---
 char[] buf;
 // ...read into buf...

 uint32_t fourcc = cast(uint32_t) buf[0..4];
 ---

 The values are the same size, and the code clearly shows my intention to
 reinterpret the byte data as an integer value. I could cast to pointers 
 and
 back, but that's kind of roundabout and then I lose automatic bounds 
 checking.

 Ah well.. There's probably an easy way I haven't thought of yet. Do 
 enlighten
 me.

The cast is illegal because char[] contains both the ptr and length and so a uint can't fit both pieces of data. For example one wouldn't expect the following to work: struct big { char* ptr; uint length; } ... big x; cast(uint)x; For your particular example you can write uint32_t fourcc = cast(uint32_t) buf[0..4].ptr; -Ben
Mar 20 2005
parent reply nod <nod_member pathlink.com> writes:
In article <d1knja$19n3$1 digitaldaemon.com>, Ben Hinkle says...
The cast is illegal because char[] contains both the ptr and length and so a 
uint can't fit both pieces of data. For example one wouldn't expect the 
following to work:
struct big {
  char* ptr;
  uint length;
}
...
big x;
cast(uint)x;

intuitiveness of the language. If I have four bytes on each side of the expression and an explicit cast, it should just work.
For your particular example you can write
  uint32_t fourcc = cast(uint32_t) buf[0..4].ptr;

-Ben 

Even after actually dereferencing the pointer, *cough*, I get some peculiar results. --- import std.stdio; // for printf import std.string; // for toStringz alias toStringz sz; int main (char[][] args) { char[] a = "alpha"; char[] z = "zebra"; printf("S: %s, I: %u P: %u\n", sz( a ), cast(uint) *a.ptr, cast(uint) a.ptr ); printf("S: %s, I: %u P: %u\n", sz( z ), cast(uint) *z.ptr, cast(uint) z.ptr ); printf("S: %s, I: %u P: %u\n", sz( a[0..4] ), cast(uint) *a[0..4].ptr, cast(uint) a[0..4].ptr ); printf("S: %s, I: %u P: %u\n", sz( z[0..4] ), cast(uint) *z[0..4].ptr, cast(uint) z[0..4].ptr ); return 0; } --- Results for DMD 1.181: #S: alpha, I: 5 P: 134567604 #S: zebra, I: 5 P: 134567620 #S: alph, I: 4 P: 134567604 #S: zebr, I: 4 P: 134567620 #Segmentation fault Results for GDC 0.10: #S: alpha, I: 97 P: 134566344 #S: zebra, I: 122 P: 134566350 #S: alph, I: 97 P: 134566344 #S: zebr, I: 122 P: 134566350 Am I venturing into the Twilight Zone here?
Mar 20 2005
next sibling parent "Ben Hinkle" <ben.hinkle gmail.com> writes:
"nod" <nod_member pathlink.com> wrote in message 
news:d1kucp$1fup$1 digitaldaemon.com...
 In article <d1knja$19n3$1 digitaldaemon.com>, Ben Hinkle says...
The cast is illegal because char[] contains both the ptr and length and so 
a
uint can't fit both pieces of data. For example one wouldn't expect the
following to work:
struct big {
  char* ptr;
  uint length;
}
...
big x;
cast(uint)x;

intuitiveness of the language. If I have four bytes on each side of the expression and an explicit cast, it should just work.

Oh - you want the _contents_ of the array to be cast. I missed that part. The expression buf[0..4] creates another dynamic array so I thought you were trying to cast the array ptr to an int. In order to get the contents you need to do something like uint fourcc = *(cast(uint*)buf.ptr)
Mar 20 2005
prev sibling parent reply Lukas Pinkowski <Lukas.Pinkowski web.de> writes:
nod wrote:
For your particular example you can write
  uint32_t fourcc = cast(uint32_t) buf[0..4].ptr;

Even after actually dereferencing the pointer, *cough*, I get some peculiar results.

You're dereferencing the wrong pointer, it should be uint fourcc = *(cast(uint*) buf[0..4].ptr);
 ---
 import std.stdio; // for printf
 import std.string; // for toStringz
 
 alias toStringz sz;
 
 int main (char[][] args)
 {
 char[] a = "alpha";
 char[] z = "zebra";
 
 printf("S: %s, I: %u P: %u\n",
 sz( a ), cast(uint) *a.ptr, cast(uint) a.ptr  );
 printf("S: %s, I: %u P: %u\n",
 sz( z ), cast(uint) *z.ptr, cast(uint) z.ptr  );
 printf("S: %s, I: %u P: %u\n",
 sz( a[0..4] ), cast(uint) *a[0..4].ptr, cast(uint) a[0..4].ptr  );
 printf("S: %s, I: %u P: %u\n",
 sz( z[0..4] ), cast(uint) *z[0..4].ptr, cast(uint) z[0..4].ptr  );
 
 return 0;
 }

Mar 20 2005
parent reply nod <nod_member pathlink.com> writes:
Lukas Pinkowski wrote:
You're dereferencing the wrong pointer, it should be

uint fourcc = *(cast(uint*) buf[0..4].ptr);

Umm yes, that's true. NTS: Never code when tired. Ben Hinkle wrote:
 Oh - you want the _contents_ of the array to be cast. I missed that part. 
 The expression buf[0..4] creates another dynamic array so I thought you were 
 trying to cast the array ptr to an int. In order to get the contents you 
 need to do something like
  uint fourcc = *(cast(uint*)buf.ptr)

Actually, what I would really like is a reference. Are there even references to scalars in D? Lukas Pinkowski, Ben Hinkle and Walter wrote:
 uint fourcc = *cast(uint *)buf.ptr;

Yup I have figured that out by now. Thanks!
Mar 21 2005
parent xs0 <xs0 xs0.com> writes:
You can use the pointer (which is about the same as a reference), or you 
can create a slice to get a bounds-checked array of size 1 (int[] 
arr=ptr[0..1]), or .. Depends on what you want to do with it..


xs0


nod wrote:
 Lukas Pinkowski wrote:
 
You're dereferencing the wrong pointer, it should be

uint fourcc = *(cast(uint*) buf[0..4].ptr);

Umm yes, that's true. NTS: Never code when tired. Ben Hinkle wrote:
Oh - you want the _contents_ of the array to be cast. I missed that part. 
The expression buf[0..4] creates another dynamic array so I thought you were 
trying to cast the array ptr to an int. In order to get the contents you 
need to do something like
 uint fourcc = *(cast(uint*)buf.ptr)

Actually, what I would really like is a reference. Are there even references to scalars in D? Lukas Pinkowski, Ben Hinkle and Walter wrote:
uint fourcc = *cast(uint *)buf.ptr;

Yup I have figured that out by now. Thanks!

Mar 21 2005
prev sibling next sibling parent Derek Parnell <derek psych.ward> writes:
On Sun, 20 Mar 2005 20:41:52 +0000 (UTC), nod wrote:

 Is there a good reason why the following should not be allowed:
 
 ---
 char[] buf;
 // ...read into buf...
 
 uint32_t fourcc = cast(uint32_t) buf[0..4];
 ---
 
 The values are the same size, and the code clearly shows my intention to
 reinterpret the byte data as an integer value. I could cast to pointers and
 back, but that's kind of roundabout and then I lose automatic bounds checking.
 
 Ah well.. There's probably an easy way I haven't thought of yet. Do enlighten
 me.

Agreed, it does get a bit confusing at times, but the phrase 'buf[0..4]' in this context is the address of a slice (dynamic array). So trying to cast a dynamic array to an integer is not going to work. Given that a dynamic array is equivalent to struct { void *data; uint length }; However, if you treat the slice as an address, you can play with that ... <code> import std.stdio; import std.stdint; void main() { char[] s = "abcdefghijiklmnopqrstuvwxyz"; uint32_t v; for(int i = 0; i <= s.length-v.sizeof; i++) { v = *(cast(uint32_t *)s[i .. i+v.sizeof]); writefln("%d 0x%08x %s ", v, v, s[i .. i+v.sizeof]); } } </code> -- Derek Melbourne, Australia 21/03/2005 10:59:44 AM
Mar 20 2005
prev sibling parent "Walter" <newshound digitalmars.com> writes:
"nod" <nod_member pathlink.com> wrote in message
news:d1kn6g$19a3$1 digitaldaemon.com...
 Is there a good reason why the following should not be allowed:

 ---
 char[] buf;
 // ...read into buf...

 uint32_t fourcc = cast(uint32_t) buf[0..4];
 ---

 The values are the same size, and the code clearly shows my intention to
 reinterpret the byte data as an integer value. I could cast to pointers

 back, but that's kind of roundabout and then I lose automatic bounds

 Ah well.. There's probably an easy way I haven't thought of yet. Do

 me.

uint fourcc = *cast(uint *)buf.ptr;
Mar 20 2005