lopez@uiucdcsp.cs.uiuc.edu (04/25/87)
Reply to Xenix Comments by Dave. Being a User of Microport's Unix System V I don't have to deal with the madness of Microsoft. The problem of having pointers that are not the same length as integers cost me a day and alot of steam. But I think that declaring: #define NULL (char *)0 is expensive but will always do the trick for all models (small,large,huge) On UNIX System V AT I had done the typical tricks in C of: if (!charptr) Even though I new it was crypt, but efficient. But all of that worked while I was in the small memory model, when I went to large I core dumped my brain. For now pointers were 32 bits instead of 16 bits, but integers are 16 bits. So after alot of frustration I figured out that NULL was defined as 0L. Which makes sense since we need a 32 bit zero value, which is not an integer. But As for people saying that if (charptr == 0) should work, "for any good C programmer's" I think thats hogwash. On every system I have ever used if (!charptr) worked, but I am happy that System V/AT has finally forced me to write code that is less crypt. if (charptr == NULL) is easier to read by everyone, and less likely to be a source of unexpected bugs. As for Microport's product, I think it is the real McCoy. Xenix is for people who have no class. Frank Lopez University of Illinois
lopez@uiucdcsp.cs.uiuc.edu (04/25/87)
A biased reply of course.
chris@mimsy.UUCP (Chris Torek) (04/26/87)
In article <77200001@uiucdcsp> lopez@uiucdcsp.cs.uiuc.edu writes: >The problem of having pointers that are not the same length as integers >cost me a day and alot of steam. But I think that declaring: >#define NULL (char *)0 >is expensive but will always do the trick for all models (small,large,huge) This is wrong: It will not always work. In fact, it will not work on at least two existing machines, both of which have C compilers. (DG MV series and PR1ME series have 48 bit char pointers, but 32 bit word (integer, structure, &c) pointers. Passing one (char *)0 and one int to a function that expects one (int *)0 followed by one int will give you a much-deserved surprise.) >On UNIX System V AT I had done the typical tricks in C of: > if (!charptr) >Even though I new [sic] it was crypt [sic], but efficient. There is really nothing illegal about this, although it is considered bad style by many. It is also no more efficient than if (charptr == NULL) or if (charptr == 0) ---both of which MUST mean the same thing, or the compiler or the environment is broken. >... after alot of frustration I figured out that NULL was defined >as 0L. Which makes sense since we need a 32 bit zero value, which >is not an integer. double pow(); extern double no; printf("%g\n", pow(no, 1000.0)); You do not need a 32 bit zero value. You need a null pointer to char. A null pointer to char is not a 32 bit zero value. It is not a 16 bit zero value. It is not an 18 bit zero value. It is not a 36 bit zero value. It is not a 48 bit zero value. It is all of these, and none. It is a null pointer to char. A null pointer to char is a null pointer to char. A null pointer to char is a null pointer to char. (What I tell you three times is true.) >But As for people saying that if (charptr == 0) should work, >"for any good C programmer's" I think thats hogwash. It has nothing to do with programmers. Any correct C *compiler* will compare `charptr' with an appropriately typed null pointer, not with a 16 bit integer zero, nor with a 32 bit integer zero, nor with an 18 bit integer zero, nor a 36 bit zero nor a 48 bit zero. All of these happen to correspond to certain machines' ideas of null pointers, but a null pointer is a null pointer, not any of these odd objects. In an assignment or comparison context when the other operand is a pointer, the integer constant value zero is converted to a null pointer of the appropriate type. In other contexts, no conversion is performed, and the programmer must provide an appropriate cast. It is legal (though unnecessary) to write if (charptr == (char *) 0) or if (charptr == (char *) NULL) It is *not* legal (with an exception mentioned below) to write n = scandir(dir, &names, NULL, NULL) because scandir wants two pointers to function returning integer. It is legal and necessary to write n = scandir(dir, &names, (int (*)()) NULL, (int (*)()) NULL) or something equivalent. If you run lint, it will properly complain about incorrect function calls. Exception: If you use a dpANS-conformant compiler with function prototypes, the function prototype can supply assignment context for function parameters, making the first of the two `scandir' calls legal. Of course, there must be a scandir prototype in scope at the time of the call. >On every system I have ever used if (!charptr) worked, (because it must) > if (charptr == NULL) > is easier to read by everyone, and less likely to be a source of > unexpected bugs. (I agree.) -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7690) UUCP: seismo!mimsy!chris ARPA/CSNet: chris@mimsy.umd.edu
guy@gorodish.UUCP (04/27/87)
>But I think that declaring: > >#define NULL (char *)0 > >is expensive but will always do the trick for all models (small,large,huge) And will also tick "lint" (and PCC, in some cases, I suspect) with some justification. >On UNIX System V AT I had done the typical tricks in C of: > > if (!charptr) > > Even though I new it was crypt, but efficient. If if (!charptr) is any more efficient than if (charptr == 0) you have some justification for flaming the author(s) of your compiler. The two constructs are equivalent, and any good compiler will produce equally efficient code for them. > So after alot of frustration I figured out that NULL was defined > as 0L. Which makes sense since we need a 32 bit zero value, which > is not an integer. No, it makes no sense whatsoever because: 1) a 32-bit zero value *is* an integer; it just doesn't happen to be an "int"; and 2) "we" don't need a 32-bit zero value, we need a null pointer of the appropriate type, and null pointers are not integers. > But As for people saying that if (charptr == 0) should work, > "for any good C programmer's" I think thats hogwash. Anyone who knows the C language well enough to make their comments on this newsgroup worth believing knows that if (charptr == 0) should work. Anyone who knows the C language well enough that they should feel competent to implement it knows that it should work.
lopez@uiucdcsp.cs.uiuc.edu (04/29/87)
>/* Written 1:45 pm Apr 27, 1987 by guy%gorodish@Sun.COM in uiucdcsp:comp.lang.c */ >you have some justification for flaming the author(s) of your >compiler. The two constructs are equivalent, and any good compiler >will produce equally efficient code for them. The above is irrelevant since I believed that the null-pointer was equivalent to (int)zero. "apparently not true" Plus I assumed a "dumb" compiler "in this day and age is very common." > > 1) a 32-bit zero value *is* an integer; it just doesn't > happen to be an "int"; True, but irrelevant: (integer was used in terms of the latter, that doesn't need explanation). > > 2) "we" don't need a 32-bit zero value, we need a null > pointer of the appropriate type, and null pointers are not > integers. paraphase: (null pointers internally are not integers) When you enter (charptr == 0) in your "C" source code, when the compiler takes its first pass and sees the zero, it will first identify it as a zero and then see that it is a special case and make the transformation. If I am wrong, tell me. for, page 97 "K&R" "In general, integers cannot meaningfully be assigned to pointers; zero is a special case." ::Quote. By definition zero is an integer. ::Math. Good argument for not having NULL being "0". ::Common Sense. If NULL is not (int)zero, then C should not be using the symbol "0" to represent it and (int)0. ::Statement. :-> but by page 97 it appears that NULL is (int)zero and that it :-> is up to the compiler to take care of the special case. Lastly, p. 192 says: "the assignment of the constant 0 to a pointer will produce a null pointer". Meaning? the pointer now has the value of zero. (or can this be seen as compiler dependent). Can each compiler writer have their own way of representing a NULL pointer (internally). We have two different types (pointers and integers) I seemed to have forgotten that; been writing too many lines of "C" lately. > >/* End of text from uiucdcsp:comp.lang.c */
guy%gorodish@Sun.COM (Guy Harris) (05/01/87)
> > 1) a 32-bit zero value *is* an integer; it just doesn't > > happen to be an "int"; > > True, but irrelevant: > (integer was used in terms of the latter, that doesn't need explanation). Oh, yes it does. The term "integral type" is used both in K&R and in the ANSI C draft, and does NOT just refer to "int". 0L is an integer in C, even though it is not (necessarily) an "int". > If NULL is not (int)zero, then C should not be using the symbol "0" > to represent it and (int)0. I agree, given all the confusion overloading the symbol "0" causes, but it's too late to fix things now. > "the assignment of the constant 0 to a pointer will produce a > null pointer". > > Meaning? the pointer now has the value of zero. > (or can this be seen as compiler dependent). Nope. The pointer now has the value of a null pointer of the appropriate type. On some implementations the pointer in question may have all its bits zero; on other implementations, it may not. > Can each compiler writer have their own way of representing > a NULL pointer (internally). I presume by "internally" you mean "internally to the generated code". (How the compiler works internally is irrelevant; it is a black box.) A compiler writer can represent NULL pointers with any bit pattern they choose, as long as NO pointer to any object will have that same bit pattern (I include tag bits, etc. here - if you have tag bits, you may represent a null pointer with the same non-tag-bits that represent a pointer to an object, as long as the tag bits are different and as long as this difference will cause a null pointer not to compare equal to said pointer value). > We have two different types (pointers and integers) We have a lot more types than that. We have several different integer types, two floating-point types (three in ANSI C), a theoretically infinite set of structure types, a theoretically infinite set of union types, a theoretically infinite set of enumerated data types (yes, I know they are considered "funny" integral types in ANSI C), and as many types of pointers, arrays, and functions as we have data types plus "pointer to void" and "function returning "void" (the set of function types is "bigger" in ANSI C in that a function's type includes the types of its arguments). (The astute reader will note that this implies that the cardinality of the set of data types is infinite; in theory, it sure is. In practice, compilers will probably impose a limit on how many levels of pointer indirection they will support, as well as limits on how many different structure, union, and enumerated types they will support.)
jimp@cognos.uucp (Jim Patterson) (05/02/87)
In article <6464@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes: >>But I think that declaring: >>#define NULL (char *)0 >>is expensive but will always do the trick for all models (small,large,huge) > >This is wrong: It will not always work. In fact, it will not work >on at least two existing machines, both of which have C compilers. >(DG MV series and PR1ME series have 48 bit char pointers, but 32 >bit word (integer, structure, &c) pointers.) I've no experience on PRIME, but I do know that the DG MV series uses 32 bit pointers exclusively (for both char and word pointers). They are represented differently (a char pointer is the corresponding word pointer shifted one bit left, with the low-order bit addressing one char of the corresponding word). However, the representation of NULL is the same, 0 in both cases. In fact, because an int is also 32 bits with DG's C compiler, there are very few reasonable ways of defining NULL that won't work over function calls (I think that all of the alternatives that have flown by this discussion would in fact work). -- Jim Patterson Cognos Inc.
roger@celtics.UUCP (Roger Klorese) (05/06/87)
In article <641@cognos.UUCP> jimp@cognos.UUCP (Jim Patterson) writes: >In article <6464@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes: >>>But I think that declaring: #define NULL (char *)0 >>>is expensive but will always do the trick for all models (small,large,huge) >> >>This is wrong: It will not always work. In fact, it will not work >>on at least two existing machines, both of which have C compilers. > >I've no experience on PRIME... Well, I DO... let's talk about it. The Prime 50 series uses a segmented architecture. The null pointer is defined as a pointer to segment 7777(octal), location 0. NULL must be defined as 0, NOT (char *)0, for the compiler and runime environment to test this properly. By the way, character pointers are indeed a 48-bit quantity, containing segment number, protection ring, location (word), and byte-offset. -- ///==\\ (No disclaimer - nobody's listening anyway.) /// Roger B.A. Klorese, CELERITY (Northeast Area) \\\ 40 Speen St., Framingham, MA 01701 +1 617 872-1552 \\\==// celtics!roger@seismo.CSS.GOV - seismo!celtics!roger