Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!mnetor!uunet!husc6!linus!philabs!micomvax!musocs!mcgill-vision!mouse From: mouse@mcgill-vision.UUCP (der Mouse) Newsgroups: comp.lang.c Subject: Re: Distinguished pointers (was Re: Weird syscall returns) Message-ID: <864@mcgill-vision.UUCP> Date: Tue, 18-Aug-87 01:24:00 EDT Article-I.D.: mcgill-v.864 Posted: Tue Aug 18 01:24:00 1987 Date-Received: Wed, 26-Aug-87 06:18:35 EDT References: <1158@copper.TEK.COM> <8317@utzoo.UUCP> <854@mcgill-vision.UUCP> Organization: McGill University, Montreal Lines: 80 [someone recommends the following, for getting distinguished FILE * values] >> char myio_no; >> char myio_null; >> #define NOFILE ((FILE *)&myio_no) >> #define NULLFILE ((FILE *)&myio_null) [then I say] > Hm. I see no guarantee that NOFILE != NULLFILE. Do it right: > FILE myio_no; > FILE myio_null; > #define NOFILE (&myio_no) > #define NULLFILE (&myio_null) I got a letter from someone I can't reply to (aimt!breck - aimt isn't in our uucp maps), asking why this change is necessary: > I would have sworn that the original would have sufficed. The two > character variables {myio_no,myio_null} are different variables and > the compiler had better put them in different locations. If you > don't mind taking the time to reply, how can NOFILE and NULLFILE be > equal in the first case? Well, since I can't mail, and there are likely others suffering from the same confusion, I'll explain. &myio_no is definitely not equal &myio_null. However, this is not true of ((FILE *)&myio_no) and ((FILE *)&myio_null). (To be sure, most common machines are byte-addressable and have C implementations that would indeed result in NOFILE != NULLFILE, but portability only among the common byte-addressable machines isn't what we're after here.) Let us postulate a word-addressed 32-bit machine (by "word" I mean a 16-bit quantity). On this machine, let us say, a natural pointer is a 32-bit quantity, meaning the address space is 8 gigabytes (2^32 x 2 bytes). A char will surely be 8 bits. A char pointer will then be a 32-bit pointer plus at least one more bit indicating which of the two chars in the addressed word the pointer points to. Now let us suppose that structures must be word-aligned (very probable on a word-addressed machine). Then also casting from (char *) to (FILE *) will probably just consist of dropping the extra bit (this is permitted by the C definition ever since K&R, see below for supporting quote). Now let us suppose that the compiler optimizes for space (possibly at the direction of the user) and puts myio_no and myio_null in the same word. Then &myio_no != &myio_null, but the only difference is in the extra bit, so ((FILE *)&myio_no) == ((FILE *)&myio_null). The legality of the postulated property of pointer conversion goes clear back to K&R, and I doubt it's changed in ANSI, because they are paying even more attention to portability than K&R were (I don't have a copy of the draft, and won't until it's available in machine-readable form). From Appendix A: C Reference Manual, 14.1, Explicit pointer conversions: Certain conversions involving pointers are permitted but have implementation-dependent aspects. [...] A pointer may be converted to any of the integral types large enough to hold it. [...] An object of integral type may be explicitly converted to a pointer. The mapping always carries an integer converted from a pointer back to the same pointer, but is otherwise machine dependent. A pointer to one type may be converted to a pointer to another type. The resulting pointer may cause addressing exceptions upon use [...]. It is guaranteed that a pointer to an object of a given size may be converted to a pointer to an object of a smaller size and back again without change. Note that nothing is said about converting a pointer to an object of a given size to a pointer to an object of a larger size, unless the original pointer was obtained by the reverse cast, which is not the case here. der Mouse (mouse@mcgill-vision.uucp)