jg@hpldola.HP.COM (Joe Gilray) (10/06/89)
Recently I've seen some discussion on the use of NULL, there was a lot of discussion but I still feel that I need the answers to the following questions: 1) what is the danger with using struct thing *ptr; . . . if (ptr != NULL) ... as apposed to struct thing *ptr; . . . if (ptr != (struct thing *)NULL) ... ? 2) Is there danger using int a, b; . . . my_func(a, NULL, b); as apposed to int a, b; . . . my_func(a, (struct thing *)NULL, b); when a) you are using function prototypes? b) you are NOT using function prototypes (like me)? Thanks for any help. -Joe Gilray
gwyn@smoke.BRL.MIL (Doug Gwyn) (10/07/89)
In article <5950001@hpldola.HP.COM> jg@hpldola.HP.COM (Joe Gilray) writes: >1) what is the danger with using > if (ptr != NULL) ... > as apposed to > if (ptr != (struct thing *)NULL) ... There is no danger, assuming the C implementation is correct. >2) Is there danger using > my_func(a, NULL, b); > as apposed to > my_func(a, (struct thing *)NULL, b); > when > a) you are using function prototypes? The only danger is that someone may port your code to a "classic C" environment and miss making the necessary edit. > b) you are NOT using function prototypes (like me)? Yes, it is erroneous to feed NULL to a function where a pointer argument is expected.
devine@shodha.dec.com (Bob Devine) (10/07/89)
In article <5950001@hpldola.HP.COM>, jg@hpldola.HP.COM (Joe Gilray) writes: > 1) what is the danger with using > struct thing *ptr; > if (ptr != NULL) ... > as opposed to: > if (ptr != (struct thing *)NULL) ... No danger. The comparison of `ptr' with NULL causes the NULL to be converted to the correct type. Look at the binary ops conversions. I consider it good coding style to put the cast there; it lets the future reader understand the code with less puzzlement. > 2) Is there danger using > int a, b; > my_func(a, NULL, b); > as apposed to > my_func(a, (struct thing *)NULL, b); You are in trouble if you do not use function prototypes if your system's pointer representation is not the same size as an int. Moreover if the pointer has some strange bit pattern representation then the NULL may not be passed correctly. Other places where a conversion takes place without the explicit cast are: in returns, assignments, and all ops. Bob Devine
chris@mimsy.UUCP (Chris Torek) (10/07/89)
In article <5950001@hpldola.HP.COM> jg@hpldola.HP.COM (Joe Gilray) writes: >1) what is the danger with using > struct thing *ptr; > if (ptr != NULL) ... [vs] > if (ptr != (struct thing *)NULL) ... > ? None. NULL (typically defined as `0' or, in newer compilers, `(void *)0') becomes a nil pointer when it is used in a comparison or assignment context where a pointer is needed. The comparison contexts that can change `0' to a particular nil pointer are `==' and `!='. Assignment contexts are comprised of assignments, casts, and prototyped arguments to functions. > my_func(a, NULL, b); [vs] > my_func(a, (struct thing *)NULL, b); > when > a) you are using function prototypes? If a prototype for my_func() is in scope at the point of the call, the only danger is confusion on the part of the reader (note that all other contexts listed above are `short range', i.e., you can simply `look near' the `0' or `NULL' to see if it is being used in an assignment context, but not so in this case). > b) you are NOT using function prototypes (like me)? If no prototype is in scope, the uncast NULL expands to 0, 0L, or (void *)0, all of which have different types than (struct thing *)0, and all of which could have different representations as well. In other words, if it works at all, that is mere luck. (Whether the luck is good or ill is a question perhaps best left unanswered.) -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@cs.umd.edu Path: uunet!mimsy!chris
ok@cs.mu.oz.au (Richard O'Keefe) (10/07/89)
In article <5950001@hpldola.HP.COM>, jg@hpldola.HP.COM (Joe Gilray) writes: > 1) what is the danger with using > struct thing *ptr; ... if (ptr != NULL) ... > as Opposed to > struct thing *ptr; ... if (ptr != (struct thing *)NULL) ... None. You can even use ... if (ptr) ... > 2) Is there danger using > int a, b; ... my_func(a, NULL, b); > as Opposed to > int a, b; ... my_func(a, (struct thing *)NULL, b); > when > a) you are using function prototypes? No. If there is a prototype in scope, passing an argument is like assignment, NULL will be converted to the appropriate pointer type. > b) you are NOT using function prototypes (like me)? Yes. You will get an int, which may not be the same size as a pointer, and if it is, may not be the same bit pattern as (struct thing *)NULL. It isn't just NULL. With some C compilers, and on some machines, the cast in struct thing *ptr; ... if (fwrite((char *)ptr, sizeof *ptr, 1, stream) != 1) ... is absolutely necessary. (The cast is (void *) in ANSI C, and is not needed if you have the prototype of fwrite() in scope.)
aep@ivan (Alex E. Pensky) (10/09/89)
In article <443@shodha.dec.com> devine@shodha.dec.com (Bob Devine) writes: >In article <5950001@hpldola.HP.COM>, jg@hpldola.HP.COM (Joe Gilray) writes: >> 2) Is there danger using >> int a, b; >> my_func(a, NULL, b); >> as apposed to >> my_func(a, (struct thing *)NULL, b); > > You are in trouble if you do not use function prototypes >if your system's pointer representation is not the same size >as an int. Moreover if the pointer has some strange bit >pattern representation then the NULL may not be passed correctly. > Even if pointers and integers are the same size and have the same representation, you are still in trouble if your compiler passes int parameters and pointer parameters via different mechanisms. In such a case, omitting both the prototype and the cast will mean that the *entire* parameter list will be received incorrectly by my_func(). Yes, such compilers exist, and yes, I have been bitten by one after forgetting the casts. ----------------------------------------------------------------------------- Alex Pensky ...!{cwjcc,decvax,pyramid,uunet}!abvax!aep (216)646-5211 Allen-Bradley Company 747 Alpha Drive, Highland Heights, OH 44143 -----------------------------------------------------------------------------
devine@shodha.dec.com (Bob Devine) (10/10/89)
In article <903@abvax.UUCP>, aep@ivan (Alex E. Pensky) writes: > Even if pointers and integers are the same size and have the same > representation, you are still in trouble if your compiler passes int > parameters and pointer parameters via different mechanisms. In such > a case, omitting both the prototype and the cast will mean that the *entire* > parameter list will be received incorrectly by my_func(). > Yes, such compilers exist, and yes, I have been bitten by one after > forgetting the casts. What different mechanisms? C only supports call-by-value for parameters (I'm ignoring the special casing of arrays here). How can pointers be passed differently than ints? It sounds like you used a broken compiler.
gwyn@smoke.BRL.MIL (Doug Gwyn) (10/11/89)
In article <448@shodha.dec.com> devine@shodha.dec.com (Bob Devine) writes: -In article <903@abvax.UUCP>, aep@ivan (Alex E. Pensky) writes: -> Even if pointers and integers are the same size and have the same -> representation, you are still in trouble if your compiler passes int -> parameters and pointer parameters via different mechanisms. - What different mechanisms? C only supports call-by-value for -parameters (I'm ignoring the special casing of arrays here). How -can pointers be passed differently than ints? It sounds like you -used a broken compiler. [This list sure has been getting a lot of GUESSWORK posted to it recently.] A simple example is that the first M integer parameters might be passed in data registers and the first N pointer parameters passed in address registers. Yes, there are compilers that follow conventions like this, and even stranger ones. They are not "broken".
chris@mimsy.UUCP (Chris Torek) (10/12/89)
>In article <903@abvax.UUCP> aep@ivan (Alex E. Pensky) writes: >>Even if pointers and integers are the same size and have the same >>representation, you are still in trouble if your compiler passes int >>parameters and pointer parameters via different mechanisms. ... In article <448@shodha.dec.com> devine@shodha.dec.com (Bob Devine) writes: > What different mechanisms? C only supports call-by-value for >parameters (I'm ignoring the special casing of arrays here). How >can pointers be passed differently than ints? It sounds like you >used a broken compiler. I dare say Mr. Pensky meant `different machine mechanisms that both implement call-by-value'. For instance, it is generally a Good Thing to pass one or two parameters in registers, rather than on the stack, on many machines. As an example, consider the 680x0 (x=0,1,2,3). On this CPU, pointers fit best in address registers (a0..a7) and integers fit best in data register (d0..d7). One could pass the first two pointer arguments in a0 and a1, and the first two integer arguments in d0 and d1 (allowing up to four arguments without any memory traffic). (Incidentally, the `special case for arrays' is at a higher level than argument passing. Arguments are expressions (rvalues) and arrays in such contexts are converted to pointers by the rule I am constantly describing. Since pointers are normally used to effect call-by-reference when needed, and since array declarations of formal parameters are quietly converted to pointer declarations, the language `fakes up' call-by-reference for arrays, but in truth something else is going on entirely.) -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@cs.umd.edu Path: uunet!mimsy!chris
scjones@sdrc.UUCP (Larry Jones) (10/12/89)
In article <448@shodha.dec.com>, devine@shodha.dec.com (Bob Devine) writes: > In article <903@abvax.UUCP>, aep@ivan (Alex E. Pensky) writes: > > Even if pointers and integers are the same size and have the same > > representation, you are still in trouble if your compiler passes int > > parameters and pointer parameters via different mechanisms. In such > > a case, omitting both the prototype and the cast will mean that the *entire* > > parameter list will be received incorrectly by my_func(). > > Yes, such compilers exist, and yes, I have been bitten by one after > > forgetting the casts. > > What different mechanisms? C only supports call-by-value for > parameters (I'm ignoring the special casing of arrays here). How > can pointers be passed differently than ints? It sounds like you > used a broken compiler. It's not call-by-value vs something else, it how you *do* the call-by-value. For example, a compiler could choose to pass three separate arguments lists: one containing the integer parms, one containing the floats, and the third containing the pointers. This is a perfectly valid implementation where passing an incorrectly typed argument can screw up all the following parameters rather than just the erroneous one. "But," I hear you cry, "why would anyone ever implement anything so stupid?!?" Well, start thinking about putting those parameter lists in registers rather than memory, and it should be obvious. ---- Larry Jones UUCP: uunet!sdrc!scjones SDRC scjones@SDRC.UU.NET 2000 Eastman Dr. BIX: ltl Milford, OH 45150-2789 AT&T: (513) 576-2070 "I have plenty of good sense. I just choose to ignore it." -Calvin
aep@ivan (Alex E. Pensky) (10/12/89)
In article <903@abvax.UUCP>, I, aep@ivan (Alex E. Pensky) wrote: >> Even if pointers and integers are the same size and have the same >> representation, you are still in trouble if your compiler passes int >> parameters and pointer parameters via different mechanisms. In such >> a case, omitting both the prototype and the cast will mean that the *entire* >> parameter list will be received incorrectly by my_func(). In article <448@shodha.dec.com> devine@shodha.dec.com (Bob Devine) responds: > What different mechanisms? C only supports call-by-value for >parameters (I'm ignoring the special casing of arrays here). How >can pointers be passed differently than ints? It sounds like you >used a broken compiler. Imagine this: Compiler supports passing in registers rather than on the stack. Motorola 68xxx compiler. Scalars are passed in data registers, pointers in address registers. foobar( (char *)NULL ) passes a 32-bit zero in register A2, but foobar( NULL ) passes a 32-bit zero in register D3 If foobar() is written to expect a char *, it will look for its argument in register A2. Who knows what's in A2, in the latter case above? Welcome to the Tektronix CLANDS II cross-development system!! No, the compiler is not broken, it's just trying to make my program run faster by reducing function call overhead. Moral of the story: If you ever assume that a cast is not really necessary when mixing types, you are writing code that is not only machine-specific, it is also COMPILER-SPECIFIC. ----------------------------------------------------------------------------- Alex Pensky ...!{cwjcc,decvax,pyramid,uunet}!abvax!aep (216)646-5211 Allen-Bradley Company 747 Alpha Drive, Highland Heights, OH 44143 -----------------------------------------------------------------------------