Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!watmath!clyde!burl!ulysses!bellcore!decvax!decwrl!sun!guy From: guy@sun.UUCP Newsgroups: net.lang.c Subject: Re: void * (was Re: malloc()) Message-ID: <3717@sun.uucp> Date: Tue, 20-May-86 14:36:17 EDT Article-I.D.: sun.3717 Posted: Tue May 20 14:36:17 1986 Date-Received: Fri, 23-May-86 07:56:04 EDT References: <3674@sun.uucp> <835@bentley.UUCP> Organization: Sun Microsystems, Inc. Lines: 119 > So, although not necessarily synonyms, they ("char *" and "void *" - gh) > do have the same properties, except that "char *" conversions usually > require a cast to be acceptable. Well, 1) they don't have the same properties - if you dereference a "char *", you get a "char", while if you dereference a "void *", you get a "void", which means you can't dereference a "void *" without casting it to a pointer to some meaningful type (this, in answer to your question below, is presumably why "void *" was chosen) 2) the fact that "char *" conversions require a cast is NOT a characteristic of the language, but a characteristic of the compiler/"lint". A C compiler which never generated any warnings about pointer conversions would not be in violation of the language specification. As such, a C compiler could, if its author wanted it to, generate warning messages about "illegal pointer combination" and about "possible pointer alignment problem" for implicit conversions (i.e., conversions not involving casts) between "char *" and other pointers, and not generate them for implicit conversions between "void *" and other pointers. It could generate both warning messages for all implicit pointer conversions, and generate them for all explicit pointer conversions except those involving "void *". A compiler which did so would not assign "char *" and "void *" the same properties, since replacing objects of type "void *" with objects of type "char *" in some expressions would cause warnings to be issued. > What I had in mind was that "ALIGN *" would be a synonym for "int *" or > whatever happens to be the most restrictive pointer type. The "guarantee" > would be as good as the "guarantee" on an "int *". I.e., not very good. Again, you would have to trust "malloc" to know what it was doing, just as you would have to do if it returned "void *". Somewhere inside the guts of "malloc" there would probably be an conversion of a "char *" to a "void *" or an "ALIGN *", and you'd have to hope that the algorithm used by "malloc" guaranteed that the pointer being converted were aligned properly. > Well, what *is* the justification for adding "void *" to the language? To > allow people to shove pointers around without casts? No. One could allow people to shove pointers around with casts simply by removing some warning messages from some current C compilers. > To make lint shut up about malloc()? In a sense, yes. It also makes it possible to use "opaque pointers" without getting complaints from the compiler. We currently run our kernel through "lint" before it goes out the door; the "lint" rules in the 4.2BSD kernel "makefile" run the "lint" output through "egrep" to eliminate "possible pointer alignment problem" messages, since there are a number of cases where there are no such problems but we have no way to tell "lint" that. If "caddr_t" were "void *" instead of "char *", we wouldn't have to strip out all "possible pointer alignment problem" messages; any that appeared would indicate that there was a real problem in the code. > Or just to distinguish "generic pointers" from pointers that can be > dereferenced? (Could be done with a typedef. So could "void", but > they put it in anyway.) You can do "void" and "caddr_t" (or whatever you want to call a "generic pointer") with "typedefs", but you can't make the compiler recognize their unique properties that way. If you do "typedef int void;", the compiler will not recognize that casting something to "void" throws its argument away, and certainly won't recognize that "void foo();" declares a function which doesn't return a value. If you declared "caddr_t foop;", the compiler would let you dereference "foop" in an expression. As such, I presume by "distinguish" you mean "distinguish *for the reader of code*", not "distinguish for the compiler". That is one thing you can use "void *" to do, but it's not the only reason it was proposed. > I do not strongly object to the addition of "void *", but I am worried about > it "hiding" errors. (I'm one of those purists who thinks that programmers > *should* use casts to change types.) Yes, if some compiler implementer misses the obvious, it could be used to hide errors. (Unfortunately, I've seen a lot of cases where implementers miss the obvious.) If one assumes that the current PCC/"lint" rules for complaining about pointer conversions are correct, the correct extension of those rules to "void *" is: implicit conversions to and from "void *" should generate "illegal pointer combination" warnings (although they need not give "possible pointer alignment problem" warnings) explicit conversions (i.e., conversions with casts) should not give any "possible pointer alignment problem" warnings; if you specify the "-c" flag to older "lint"s, or the "-p" flag to newer ones (both of which turn on the "complain about all pointer casts" flag - older versions give "illegal pointer combination" warnings, and newer ones give "pointer casts may be troublesome"), it should probably continue to give warnings. This means that if you're going to toss pointers around casually, the compiler is at least going to warn you about it; you have to say "I know what I'm doing, shut up" by adding casts if you don't want errors. In fact, I would suggest that all conversions between pointers other than "void *" should get "illegal pointer combination" (or, perhaps, "questionable pointer combination", at least in some cases, since the C standard does permit certain combinations) warnings, even if casts are used. > Also, it's a misnomer; it has nothing to do with "void". I presume the reason why "void *" was chosen is, as stated above, that a pointer of type "void *" would, when dereferenced, yield an object of type "void", and as such dereferencing a "void *" would be illegal, just as using a function of type "void" as if it returned a value would be. -- Guy Harris {ihnp4, decvax, seismo, decwrl, ...}!sun!guy guy@sun.arpa