Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP
Path: utzoo!mnetor!uunet!seismo!husc6!cmcl2!brl-adm!adm!bilbo.dobson@CS.UCLA.EDU
From: bilbo.dobson@CS.UCLA.EDU (Peter Dobson)
Newsgroups: comp.lang.c
Subject: Re: Distinguished pointers (was Re: Weird syscall returns)
Message-ID: <8383@brl-adm.ARPA>
Date: Tue, 21-Jul-87 21:17:56 EDT
Article-I.D.: brl-adm.8383
Posted: Tue Jul 21 21:17:56 1987
Date-Received: Thu, 23-Jul-87 06:43:17 EDT
Sender: news@brl-adm.ARPA
Lines: 53

> From: Rahul Dhesi 
> Newsgroups: comp.lang.c
> Subject: Distinguished pointers (was Re: Weird syscall returns)
> Date: 15 Jul 87 16:14:16 GMT
> To:       info-c@brl-smoke.arpa

In article <846@bsu-cs.UUCP> dhesi@bsu-cs.uucp (Rahul Dhesi) writes:

> On the contrary, I think we need more distinguished pointer values, not
> just a single zero or NULL value.  I have a set of custom I/O routines
> that use the pointer value NOFILE to indicate that no file could be
> opened (equivalent to (char *) 0 in current C implementations) and
> another pointer value NULLFILE to indicate that the custom I/O library
> routines should ignore all output to this file (equivalent to the value
> (char *) -1 but conceptually equivalent to opening /dev/null for
> output, except that a file descriptor isn't wasted and the existence of
> a null device or its name need not be presumed).

> Consider again how gets(3) indicates end-of-file and error.  If there
> were two distinguished pointer values, one could test for both
> end-of-file and for error without using the botched-up errno.

> Upward compatibility will prohibit doing this for gets(), but the need
> for more than one distinguished pointer is clear.  We already have a
> (char *) -1; let's just give it a different name and keep it.  Then
> sbrk can return ERRPTR on error, and we can define ERRPTR as 
> (char *) -1, and remain fully compatible to boot.
> -- 
> Rahul Dhesi         UUCP:  {ihnp4,seismo}!{iuvax,pur-ee}!bsu-cs!dhesi

A portable way to do this is to declare a global data object
that is just used as a location for a pointer to point to, like:

    /* outside a function declaration */
    char nofile, nullfile;

    #define NULLFILE &nullfile
    #define NOFILE &nofile

This way the pointers will be valid values on all machines, and
won't contain a value that is valid in a pointer to point to any
data object (as the characters nullfile, and nofile aren't
used.)

This may fail on machines where pointers can't be cast from type
(char *) to another type and back again.  For example in
MicroSoft C on MS-DOS in some memory models a pointer to
character cast to pointer to function, cast back to pointer to
function, doesn't work.  I don't think this is likely to be a
problem on any implementations where all the pointer types point
to data.

--- Peter