[comp.lang.c] canonical values - an amenity

garry@batcomputer.tn.cornell.edu (Garry Wiegand) (11/19/86)

The new C incipient-spec has a primitive datatype called "void *". It has
the property that a pointer of any type cast to (void *) and back again
is guaranteed to emerge unharmed.

I use this heavily to pass pointers (to structures) through utility routines
which do not know what type of pointer is coming down, and back again to
action routines which *do* know what type is coming.

What I would like is to be able to do the same thing with *any* kind of
(primitive) value, not merely pointer values!!! (Why do things half-way 
in the language ??)

On many/most machines, "unknown" (somebody was brain-damaged when they
overloaded the word "void"!) would be equivalent to:

	(unknown)char ->    (double)char
	(unknown)pointer -> (double)(long)pointer
	(unknown)short ->   (double)short
	(unknown)long ->    (double)long
	(unknown)int ->     (double)int
	(unknown)float ->   (double)float

I can get away with this because doubles almost always have more
precision in them than any of the other datatypes. I can't
#define "unknown" as "double" because (unknown)pointer will break
on many (broken) compilers. It can't be (double)(long) because
(unknown)float will break. So I need it as a primitive. Ideally
it would just be a 64-bit bitmask internally rather than a double,
to avoid unnecessary conversions.

A fringe benefit is that I can declare *actual variables* to be of
type "unknown", and so avoid having to play with unions of {int, char,
float, double, void *}. 

Tests for equality should still work. Tests for ordering (<, >) would 
work easily on a doubles-implementation but might be tough on bitmasks.

Yah, I know I'm too late. Can I at least have (double)pointer not break,
pleeez? Does the spec already say that (double)pointer is as legit as
and equivalent to (double)(long)(void *)pointer ??

garry wiegand   (garry%cadif-oak@cu-arpa.cs.cornell.edu)

karl@haddock.UUCP (Karl Heuer) (12/05/86)

In article <1542@batcomputer.tn.cornell.edu> garry%cadif-oak@cu-arpa.cs.cornell.edu.arpa writes:
>I use [void *] heavily to pass pointers (to structures) through utility
>routines which do not know what type of pointer is coming down, and back
>again to action routines which *do* know what type is coming.
>
>What I would like is to be able to do the same thing with *any* kind of
>(primitive) value, not merely pointer values!!!

There are a few routines, e.g. memcpy(), which can behave reasonably on any
pointer type (cast into "void *").  I find it hard to imagine a routine that
would operate portably on both "double" and "char *" without knowing which.

>... So I need it as a primitive. Ideally it would just be a 64-bit bitmask
>internally rather than a double, to avoid unnecessary conversions.

From this I assume that you want "(double)unk" and "(int)unk" to just read
the bits directly and not convert -- in other words, the operation performed
by a union rather than a cast.

>A fringe benefit is that I can declare *actual variables* to be of
>type "unknown", and so avoid having to play with unions of {int, char,
>float, double, void *}. 

You can declare actual variables of type union { int, ... }.

Let me make a counterproposal (one which is more likely to be accepted by
the C community):
    typedef union { int asint; char *asstring; double asreal; } universe;
    universe u;  int i;
    ...
    u = (universe)i;
This cast (currently illegal) would be equivalent to "u.asint = i", but is
more powerful since it can be used in contexts other than assignment.  For
example, I could now initialize an array of unions at compile time:
    universe a[] = { (universe)12, (universe)"hello", (universe)5.6 };

The reverse cast "(int)u" could be allowed for completeness, but wouldn't
be as useful since "u.asint" provides the same functionality.

Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint

throopw@dg_rtp.UUCP (Wayne Throop) (12/08/86)

> karl@haddock.UUCP (Karl Heuer)
> Let me make a [proposal]
> the C community):
>    typedef union { int asint; char *asstring; double asreal; } universe;
>    universe u;  int i;
>    ...
>    u = (universe)i;

Oooooooh!  I LIKE it.  But I'd druther have the general ability to coin
struct and union constants... passing small structs full of bitfields to
functions that are manufactured out of integers on the fly is a more
common problem.

--
A LISP programmer knows the value of everything, but the cost of nothing.
                                --- Alan J. Perlis
-- 
Wayne Throop      <the-known-world>!mcnc!rti-sel!dg_rtp!throopw

jsdy@hadron.UUCP (Joseph S. D. Yao) (12/15/86)

In article <1542@batcomputer.tn.cornell.edu> garry%cadif-oak@cu-arpa.cs.cornell.edu.arpa writes:
>the property that a pointer of any type cast to (void *) and back again
>is guaranteed to emerge unharmed.
>What I would like is to be able to do the same thing with *any* kind of
>(primitive) value, not merely pointer values!!! (Why do things half-way 
>in the language ??)
>	(unknown)pointer -> (double)(long)pointer
>	(unknown)long ->    (double)long

Unfortunately, there's no guarantee that a double will not lose
low-order bits in the mantissa when converting a long.  This is
especially a problem if the "long" happens to be a pointer.  E.g.,
32-bit long 0x7fffffff to 32-bit double with 8-bit exponent and
24-bit mantissa loses 8 bits of precision.  (Just f'r'instance.)
Unions are sometimes used for this purpose: they are guaranteed
to be as large as the largest object contained therein.
-- 

	Joe Yao		hadron!jsdy@seismo.{CSS.GOV,ARPA,UUCP}
			jsdy@hadron.COM (not yet domainised)