Subject: Re: couple of toolchain questions
To: der Mouse <mouse@Rodents.Montreal.QC.CA>
From: Andy Isaacson <adi@hexapodia.org>
List: tech-userlevel
Date: 06/18/2002 16:07:51
On Tue, Jun 18, 2002 at 11:00:28AM -0400, der Mouse wrote:
> > 	there seem to be pointer-casting bug (or portability issue) in
> > 	GNU toolchain.  they try to cast void * (or whatever pointer) to
> > 	unsigned long long, under certain configuration, and it fails to
> > 	compile.
> 
> Is there any guarantee that _any_ integer type is large enough to hold
> a pointer without loss of information?  I'm pretty sure there isn't in
> second-edition K&R C (which is fairly close to the first ANSI/ISO C)...

There is a guarantee that there is SOME integer type which is large
enough to hold a pointer without losing information.  There is a
guarantee that 'long int' is at least as large as every other standard
integer type.  Together those imply that compliant C90 implementations
guarantee pointers can be cast to long without loss of information.

The second requirement was relaxed in C99 at the behest of Microsoft and
legacy UNIX vendors.  The C99 standard makes 'long long' larger than
'long int', and defines a bunch of new types in <stdint.h>.  The Win64
programming model is IL32LLP64, because microsoft hard-coded the
assumption "long is 32 bits" throughout their APIs, including on-disk
formats.  Some UNIX vendors got significant pressure from customers to
preserve the "long is 32 bits" assumption, too.

So, on C90 platforms, it is safe to cast a pointer to a long.  On c99
platforms, it is safe to cast a pointer to an intptr_t after including
<stdint.h>.  Pick your poison.

> > 		void *p;
> > 		unsigned long long x;
> > 		x = (unsigned long long)p;
> > 	i've modified my local tree as below, basically doing:
> > 		x = (unsigned long long)(unsigned long)p;
> 
> Are there machines where pointers are larger than long but not as large
> as long long?  If so, that loses information unnecessarily....

Ah, there's one more caveat:  GCC issues the same warning for casting a
64-bit pointer to a 32-bit type (which can lose information) as it does
for casting a 32-bit pointer to a 64-bit type (which cannot lose
information).  So you cannot replace the C90 code

    long foo = (long)p;

with the (non-C90 but widely supported) code

    long long foo = (long long)p;

if you want your code to compile with -Wall -Werror on 32-bit platforms.

-andy