ckl@uwbln.UUCP (Christoph Kuenkel) (02/02/89)
Can anyone please enlighten me what the discussion is about? Why at all should I ever use NULL anywhere? My impression is, that a) it does not work as one expects and b) its not needed anyway. I simply never use it and never had problems. Furthermore, I think its much more obvious to write 0, when I mean zero, ((char *) 0) when I mean a zero character pointer, etc. etc. Do I miss something? Christoph -- # include <std/disclaimer.h> Christoph Kuenkel/UniWare GmbH Kantstr. 152, 1000 Berlin 12, West Germany ck@tub.BITNET ckl@uwbln {unido,tmpmbx,tub}!uwbln!ckl
gwyn@smoke.BRL.MIL (Doug Gwyn ) (02/04/89)
In article <1340@uwbull.uwbln.UUCP> ckl@uwbln.UUCP (Christoph Kuenkel) writes: >Why at all should I ever use NULL anywhere? Some think that use of a mnemonic makes the code more intelligible. If C were being designed now, I would recommend that "nil" be made a language keyword. >its much more obvious to write 0, when I mean zero, ((char *) 0) when >I mean a zero character pointer, etc. etc. Using 0 instead of NULL is perfectly acceptable.
cramer@optilink.UUCP (Clayton Cramer) (02/17/89)
In article <9582@smoke.BRL.MIL., gwyn@smoke.BRL.MIL (Doug Gwyn ) writes: . In article <1340@uwbull.uwbln.UUCP. ckl@uwbln.UUCP (Christoph Kuenkel) writes: . .Why at all should I ever use NULL anywhere? . . Some think that use of a mnemonic makes the code more intelligible. . If C were being designed now, I would recommend that "nil" be made . a language keyword. . . .its much more obvious to write 0, when I mean zero, ((char *) 0) when . .I mean a zero character pointer, etc. etc. . . Using 0 instead of NULL is perfectly acceptable. No it isn't. Segmented architecture machines will have problems with that in large model. Microsoft defines NULL as 0L, not 0, in large model. Pushing an int 0 instead of a long 0 will screw you royally on the PC. -- Clayton E. Cramer {pyramid,pixar,tekbspa}!optilink!cramer Disclaimer? You must be kidding! No company would hold opinions like mine!
chris@mimsy.UUCP (Chris Torek) (02/19/89)
>In article <9582@smoke.BRL.MIL> gwyn@smoke.BRL.MIL (Doug Gwyn) writes: >>Using 0 instead of NULL is perfectly acceptable. In article <965@optilink.UUCP> cramer@optilink.UUCP (Clayton Cramer) substitutes too many `>'s (I patched the references line) and writes: >No it isn't. Segmented architecture machines will have problems with >that in large model. Microsoft defines NULL as 0L, not 0, in large >model. Pushing an int 0 instead of a long 0 will screw you royally >on the PC. Doug Gwyn is right; you are reading things into his posting that are not there. Using 0 wherever NULL is strictly legal will always work. Never mind the fact that, by trickery, Microsoft C defines NULL in a way that works for INCORRECT calls in large model (but *not* for medium nor compact models), as a concession to bad programmers' wrong programs. Time for another rerun.... From: chris@mimsy.UUCP (Chris Torek) Newsgroups: comp.lang.c Subject: Why NULL is 0 Summary: you have seen this before, but this one is for reference Date: 9 Mar 88 02:26:10 GMT (You may wish to save this, keeping it handy to show to anyone who claims `#define NULL 0 is wrong, it should be #define NULL <xyzzy>'. I intend to do so, at any rate.) Let us begin by postulating the existence of a machine and a compiler for that machine. This machine, which I will call a `Prime', or sometimes `PR1ME', for obscure reasons such as the fact that it exists, has two kinds of pointers. `Character pointers', or objects of type (char *), are 48 bits wide. All other pointers, such as (int *) and (double *), are 32 bits wide. Now suppose we have the following C code: main() { f1(NULL); /* wrong */ f2(NULL); /* wrong */ exit(0); } f1(cp) char *cp; { if (cp != NULL) *cp = 'a'; } f2(dp) double *dp; { if (dp != NULL) *dp = 2.2; } There are two lines marked `wrong'. Now suppose we were to define NULL as 0. Clearly both calls are then wrong: both pass `(int)0', when the first should be a 48 bit (char *) nil pointer and the second a 32 bit (double *) nil pointer. Someone claims we can fix that by defining NULL as (char *)0. Suppose we do. Then the first call is correct, but the second now passes a 48 bit (char *) nil pointer instead of a 32 bit (double *) nil pointer. So much for that solution. Ah, I hear another. We should define NULL as (void *)0. Suppose we do. Then at least one call is not correct, because one should pass a 32 bit value and one a 48 bit value. If (void *) is 48 bits, the second is wrong; if it is 32 bits, the first is wrong. Obviously there is no solution. Or is there? Suppose we change the calls themselves, rather than the definition of NULL: main() { f1((char *)0); f2((double *)0); exit(0); } Now both calls are correct, because the first passes a 48 bit (char *) nil pointer, and the second a 32 bit (double *) nil pointer. And if we define NULL with #define NULL 0 we can then replace the two `0's with `NULL's: main() { f1((char *)NULL); f2((double *)NULL); exit(0); } The preprocessor changes both NULLs to 0s, and the code remains correct. On a machine such as the hypothetical `Prime', there is no single definition of NULL that will make uncasted, un-prototyped arguments correct in all cases. The C language provides a reasonable means of making the arguments correct, but it is not via `#define'. -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris
bill@twwells.uucp (T. William Wells) (02/19/89)
In article <965@optilink.UUCP> cramer@optilink.UUCP (Clayton Cramer) writes:
: . Using 0 instead of NULL is perfectly acceptable.
:
: No it isn't. Segmented architecture machines will have problems with
: that in large model. Microsoft defines NULL as 0L, not 0, in large
: model. Pushing an int 0 instead of a long 0 will screw you royally
: on the PC.
Here we go again.
Microsoft can do what they damn well please. But they are not the
authority on C.
Microsoft, like many compilers, supports pointers that are of
different sizes. Because of such compilers, passing 0 OR NULL to a
function is wrong, *wrong*, WRONG and may result in code that is
broke, *broke*, BROKE!!!!!!!
Now, for all you out there who want to know what is really going on,
here's the scoop. When you pass a zero to a function, the compiler
assumes that you mean a zero *integer*. However, if the function
receiving the argument wants a pointer, you may not get the result
you want. Some examples (for the Microsoft compiler):
foo(ptr, n)
far char *ptr; /* this might be implicitly far */
int n;
...
#define NULL 0 /* this comes from an include file. */
foo(NULL, 12)
The generated code looks something like this:
push 12 | will be interpreted as high word of ptr
push 0 | will be interpreted as low word of ptr
call foo | and foo will get random value for n.
On the other hand, consider this:
foo(ptr, n)
near char *ptr;
int n;
...
#define NULL 0L
foo(NULL, 12)
push 12 | this gets ignored
push 0 | is used for n
push 0 | is used for the pointer
call foo
Here's another failure mode:
foo(fptr, n)
int (*fptr)();
int n;
{
...
foo(NULL, 42);
This code will fail when data pointers are a different size from
function pointers.
Think about these examples and consider what what happens if you use
NULL in some program and then discover that you need more than 64K of
code or data. Boy are you screwed.
So, what's the right way?
Either provide a prototype for foo, the appropriate one of:
foo(far char *ptr, int n)
foo(near char *ptr, int n)
foo(int (*fptr)(), int n)
that is in scope when foo is called, or call foo with one of:
foo((far char *)0, 12)
foo((near char *)0, 12)
foo((int (*fptr)())0, 42)
(or a reasonable facsimile), or, if you are feeling verbose,
foo((far char *)NULL, 12)
foo((near char *)NULL, 12)
foo((int (*fptr)())NULL, 42)
AND NEVER PASS BARE 0 OR NULL AS A POINTER ARGUMENT!
---
Bill
{ uunet!proxftl | novavax } !twwells!bill
gwyn@smoke.BRL.MIL (Doug Gwyn ) (02/19/89)
In article <965@optilink.UUCP> cramer@optilink.UUCP (Clayton Cramer) writes: -In article <9582@smoke.BRL.MIL., gwyn@smoke.BRL.MIL (Doug Gwyn ) writes: -. In article <1340@uwbull.uwbln.UUCP. ckl@uwbln.UUCP (Christoph Kuenkel) writes: -. .its much more obvious to write 0, when I mean zero, ((char *) 0) when -. .I mean a zero character pointer, etc. etc. -. Using 0 instead of NULL is perfectly acceptable. -No it isn't. Segmented architecture machines will have problems with -that in large model. Microsoft defines NULL as 0L, not 0, in large -model. Pushing an int 0 instead of a long 0 will screw you royally -on the PC. It is always non-portable to pass the macro NULL, or 0 or 0L for that matter, as a pointer argument to a function without casting it to the correct pointer type. MicroSoft's definition appears to have been an ill-considered attempt to make sloppily-written code have a greater chance of working when compiled in their environment. However, such code won't port correctly to other systems until the misusage of NULL is fixed anyway. There is nothing "magic" about NULL as defined by <stdio.h> etc. It's just a mnemonic for 0, ((void*)0), or some similar expression. The C language itself guarantees that the programmer can use unadorned 0 in pointer comparisons, assignments, etc. Given the way some vendors have botched the definition of NULL, it may even be advisable to avoid using the NULL macro. It is never *necessary* to use it in portable C programming.
cramer@optilink.UUCP (Clayton Cramer) (02/22/89)
In article <399@twwells.uucp:, bill@twwells.uucp (T. William Wells) writes: : In article <965@optilink.UUCP: cramer@optilink.UUCP (Clayton Cramer) writes: : : . Using 0 instead of NULL is perfectly acceptable. : : : : No it isn't. Segmented architecture machines will have problems with : : that in large model. Microsoft defines NULL as 0L, not 0, in large : : model. Pushing an int 0 instead of a long 0 will screw you royally : : on the PC. : : Here we go again. : : Microsoft can do what they damn well please. But they are not the : authority on C. I never claimed differently. But the use of NULL when that's what you mean will save someone some headaches when it comes time to port a program to a segmented arguments. : Microsoft, like many compilers, supports pointers that are of : different sizes. Because of such compilers, passing 0 OR NULL to a : function is wrong, *wrong*, WRONG and may result in code that is : broke, *broke*, BROKE!!!!!!! Not true. In large model, stdio.h defines NULL to be 0L. NULL requires no casting to work correctly with the Microsoft C compiler. : Now, for all you out there who want to know what is really going on, : here's the scoop. When you pass a zero to a function, the compiler : assumes that you mean a zero *integer*. However, if the function : receiving the argument wants a pointer, you may not get the result : you want. Some examples (for the Microsoft compiler): : : foo(ptr, n) : far char *ptr; /* this might be implicitly far */ : int n; : ... : : #define NULL 0 /* this comes from an include file. */ Wrong. The stdio.h file defines NULL as 0L in large model, and 0 for the small model. : foo(NULL, 12) : : The generated code looks something like this: : : push 12 | will be interpreted as high word of ptr : push 0 | will be interpreted as low word of ptr : call foo | and foo will get random value for n. : : On the other hand, consider this: : : foo(ptr, n) : near char *ptr; : int n; : ... : : #define NULL 0L : : foo(NULL, 12) : : push 12 | this gets ignored : push 0 | is used for n : push 0 | is used for the pointer : call foo : : Here's another failure mode: : : foo(fptr, n) : int (*fptr)(); : int n; : { : ... : foo(NULL, 42); : : This code will fail when data pointers are a different size from : function pointers. That's why you don't #define NULL yourself -- use the stdio.h file. : Think about these examples and consider what what happens if you use : NULL in some program and then discover that you need more than 64K of : code or data. Boy are you screwed. : : So, what's the right way? : : Either provide a prototype for foo, the appropriate one of: : : foo(far char *ptr, int n) : foo(near char *ptr, int n) : foo(int (*fptr)(), int n) : : that is in scope when foo is called, or call foo with one of: : : foo((far char *)0, 12) : foo((near char *)0, 12) : foo((int (*fptr)())0, 42) : : (or a reasonable facsimile), or, if you are feeling verbose, : : foo((far char *)NULL, 12) : foo((near char *)NULL, 12) : foo((int (*fptr)())NULL, 42) : : AND NEVER PASS BARE 0 OR NULL AS A POINTER ARGUMENT! : : --- : Bill Never pass bare 0 as a pointer argument -- but use the stdio.h definition of NULL, and the segmented architecture will NOT screw you. Unless you are engaged in mixed model programming (only for the experienced programmer), there's no need to declare anything to be "near" or "far" -- the compiler and the preprocessor do the whole job for you. -- Clayton E. Cramer {pyramid,pixar,tekbspa}!optilink!cramer Disclaimer? You must be kidding! No company would hold opinions like mine!
cramer@optilink.UUCP (Clayton Cramer) (02/22/89)
In article <16020@mimsy.UUCP>, chris@mimsy.UUCP (Chris Torek) writes: > >In article <9582@smoke.BRL.MIL> gwyn@smoke.BRL.MIL (Doug Gwyn) writes: > >>Using 0 instead of NULL is perfectly acceptable. > > In article <965@optilink.UUCP> cramer@optilink.UUCP (Clayton Cramer) > substitutes too many `>'s (I patched the references line) and writes: > >No it isn't. Segmented architecture machines will have problems with > >that in large model. Microsoft defines NULL as 0L, not 0, in large > >model. Pushing an int 0 instead of a long 0 will screw you royally > >on the PC. > > Doug Gwyn is right; you are reading things into his posting that > are not there. Using 0 wherever NULL is strictly legal will always > work. Never mind the fact that, by trickery, Microsoft C defines NULL > in a way that works for INCORRECT calls in large model (but *not* for > medium nor compact models), as a concession to bad programmers' wrong > programs. This is not correct. Microsoft C defines NULL in a way that works for CORRECT calls in large model, and in medium and compact models. "Using 0 whereever NULL is strictly legal" will not work in Microsoft C, and because Microsoft has come up with the correct solution for an otherwise damaged architecture. Chris' additional comments make a distinction between data and code pointers. This will be a problem in compact and medium models (only), as described on page 142, section 6.3.3 of the "Microsoft C Optimizing Compiler User's Guide": Note that in medium and compact models, NULL must be used carefully in certain situations. NULL actually represents a null data pointer. In memory models where code and data pointers are the same size, it can be used with either. However, in memory models where code and data pointers are different sizes, this is not the cas. Consider the following example: And they show a similar example to Chris. Note that they have erred on the side of screwing up code pointers, not data pointers, since data pointers are FAR more common in C than code pointers. Note also that most programs of any great complexity end up in large model on the PC, not medium or compact. -- Clayton E. Cramer {pyramid,pixar,tekbspa}!optilink!cramer Disclaimer? You must be kidding! No company would hold opinions like mine!
chris@mimsy.UUCP (Chris Torek) (02/22/89)
>In article <16020@mimsy.UUCP> I wrote: >>... Using 0 wherever NULL is strictly legal will always work. Never >>mind the fact that, by trickery, Microsoft C defines NULL in a way that >>works for INCORRECT calls in large model (but *not* for medium nor >>compact models), as a concession to bad programmers' wrong programs. In article <975@optilink.UUCP> cramer@optilink.UUCP (Clayton Cramer) writes: >This is not correct. Microsoft C defines NULL in a way that works >for CORRECT calls in large model, and in medium and compact models. Let me put it in as few words as possible: If you do it my way, it always works. If you do it your way, it sometimes works. Now, which do you prefer? -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris
Don_A_Corbitt@cup.portal.com (02/23/89)
Clayton, Counter example time for MSC and NULL. (We already know of many counter examples for other machines, such as Pyramid...) Compact model (data pointer 32 bit, function pointer 16 bit). Function that has a function pointer argument called if error occurs (or calls exit() if no error handler passed in...) void DoSomething(int p1, int p2, void (*errhand)(int)); (oops - make this medium model - 32 bit code pointer, 16 bit data) Call DoSomething with no function prototype: (and no error handler) DoSomething(100, 200, NULL); NULL is defined as 0 (16 bits). DoSomething detects an error, checks the errhand parameter, it is not 0 (32 bits), so it calls the function. If you cast NULL to a function pointer, it will pass a 32 bit pointer, and all is well. Don_A_Corbitt@cup.portal.com
gwyn@smoke.BRL.MIL (Doug Gwyn ) (02/23/89)
In article <973@optilink.UUCP> cramer@optilink.UUCP (Clayton Cramer) writes: >Never pass bare 0 as a pointer argument -- but use the stdio.h >definition of NULL, and the segmented architecture will NOT screw >you. Wrong. Use of uncast NULL as an argument to a function is never correct usage; although you can get away with it sometimes, it only "works" by accident and may quit working suddenly if the implementation changes. It is definitely not portable. Always cast 0 or NULL to the correct pointer type when used as a function argument.
mveao@cbnews.ATT.COM (eric.a.olson) (02/23/89)
I always felt that the major benefit to be derived from using NULL where a pointer to 0 is called for is that it makes you feel so good when you stop doing it. :-) eric olson eao@mvuxq.att.com
djones@megatest.UUCP (Dave Jones) (02/23/89)
From article <16069@mimsy.UUCP>, by chris@mimsy.UUCP (Chris Torek): > > Let me put it in as few words as possible: > > If you do it my way, it always works. > > If you do it your way, it sometimes works. > Most elegantly stated. Is it true that a fundamentalist Hackers' cult in Berkeley has offered $5 million to anyone is obliterates NULL, the ultimate SLM? Probably just a rumor. Dave J.
piet@ruuinf (Piet van Oostrum) (02/23/89)
In article <973@optilink.UUCP>, cramer@optilink (Clayton Cramer) writes: `In article <399@twwells.uucp:, bill@twwells.uucp (T. William Wells) writes: `: In article <965@optilink.UUCP: cramer@optilink.UUCP (Clayton Cramer) writes: `: : . Using 0 instead of NULL is perfectly acceptable. `: : `: : No it isn't. Segmented architecture machines will have problems with `: : that in large model. Microsoft defines NULL as 0L, not 0, in large `: : model. Pushing an int 0 instead of a long 0 will screw you royally `: : on the PC. `: And on and on and on and on ..... You are all wrong. ANSI C says that the CONSTANT 0 used in a pointer context should always give the ``null'' pointer for that pointer type. BUT It must be clear from the context that a pointer type is required. The only good way to give a null pointer to a function is to write funct ( (foo *) 0 ); ^^^^^^^ i.e cast it. If you have function prototypes, the cast will be done by the compiler. Even if you want to use NULL you have to write: funct ( (foo *) NULL ); If you don't cast, it may work on your particular compiler, but some day it will hit you, unless you throw away your program before anybody else gets a chance to use it. -- Piet van Oostrum, Dept of Computer Science, University of Utrecht Padualaan 14, P.O. Box 80.089, 3508 TB Utrecht, The Netherlands Telephone: +31-30-531806. piet@cs.ruu.nl (mcvax!hp4nl!ruuinf!piet)
mcdonald@uxe.cso.uiuc.edu (02/24/89)
Subject is the flame wars resulting from the never-ending NULL (presumable pointer) affairs. Chris Torek claims (correctly) that if one wishes to pass a null pointer to a subroutine, that if you cast it to the proper type, it will work: sub((char *)0); /* pass a character pointer*/ subd((double *)0); /* pass a pointer to double */ I ask: Is it not possible to do away with this if one uses functions prototypes? Is this correct (I mean, ABSOLUTELY correct?) void sub(char *); void subd(double *); sub(0); subd(0); void sub(char * xchar) { ... } void sub(double *ddouble) { ... } I ask this as a question, not as a proposition of a flame. I have written a lot of programs for mixed (VERY mixed) model programs on the PC, and used strict prototypes for all. They seem to work fine. I never cast anything in arguments, unless it is a signed to unsigned (or vice-versa) conversion, and in that case I am paranoid enough to write out each step explicitly. Am I doing a no-no? Doug McDonald
heather@SEAS.UCLA.EDU (02/24/89)
In article <9684@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes: >In article <973@optilink.UUCP> cramer@optilink.UUCP (Clayton Cramer) writes: >>Never pass bare 0 as a pointer argument -- but use the stdio.h >>definition of NULL, and the segmented architecture will NOT screw >>you. > >Wrong. Use of uncast NULL as an argument to a function is never correct >usage; although you can get away with it sometimes, it only "works" by >accident and may quit working suddenly if the implementation changes. >It is definitely not portable. Always cast 0 or NULL to the correct >pointer type when used as a function argument. Excuse me for a probably naive question that I've had since following the discussion of passing NULL to functions: Why doesn't the C standard treat NULL or 0 (a static/constant NULL or 0, i.e. indicated at compile time) passed to a function that has a pointer value in the function prototype as a special case and do the cast implicitly? Heather Burris, UCLA
gwyn@smoke.BRL.MIL (Doug Gwyn ) (02/24/89)
In article <20928@shemp.CS.UCLA.EDU> heather@SEAS.UCLA.EDU (Heather Burris) writes: >Why doesn't the C standard treat NULL or 0 (a static/constant NULL or 0, >i.e. indicated at compile time) passed to a function that has a pointer >value in the function prototype as a special case and do the cast implicitly? It does (actually it's not a special case), but most existing C code does not use prototypes, in which case the programmer has to explicitly cast the NULL argument to the proper type.
wietse@wzv.UUCP (Wietse Z. Venema) (02/24/89)
In article <973@optilink.UUCP> cramer@optilink.UUCP (Clayton Cramer) writes: > >Never pass bare 0 as a pointer argument -- but use the stdio.h >definition of NULL, and the segmented architecture will NOT screw >you. > Wrong. Think of the middle memory model of microsoft c where sizeof(data pointer) != sizeof(function pointer). One should NEVER rely on a universal representation of null pointers. As written in a recent article, NULL is a mistake. -- work: wswietse@eutrc3.uucp | Eindhoven University of Technology work: wswietse@heitue5.bitnet | Mathematics and Computing Science home: wietse@wzv.uucp | 5600 MB Eindhoven, The Netherlands
chris@mimsy.UUCP (Chris Torek) (02/24/89)
In article <20928@shemp.CS.UCLA.EDU> heather@SEAS.UCLA.EDU writes: >Excuse me for a probably naive question that I've had since following the >discussion of passing NULL to functions: Why doesn't the C standard >treat NULL or 0 (a static/constant NULL or 0, i.e. indicated at compile time) >passed to a function that has a pointer value in the function prototype >as a special case and do the cast implicitly? This is a perfectly reasonable question, with a perfectly reasonable answer. It is not a special case and it works just fine. The key is the phrase `function prototype': Not all compilers handle prototypes, and not all programs include prototypes. If the compiler does not *know* that the first argument to strtok() has type `char *', it cannot convert a 0 argument to a nil-pointer-to-char. It passes an int-0 (or, with Microsoft's `0L' definition, a long-0) simply because it does not know any better. Give it the information (in the form of a prototype declaration, or a cast at invocation, or both) and it does the conversion. -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris
guy@auspex.UUCP (Guy Harris) (02/25/89)
>Excuse me for a probably naive question that I've had since following the >discussion of passing NULL to functions: Why doesn't the C standard >treat NULL or 0 (a static/constant NULL or 0, i.e. indicated at compile time) >passed to a function that has a pointer value in the function prototype >as a special case and do the cast implicitly? It does. (It's not really a "special case"; conversions in calls to functions with a prototype in scope are just like other conversions - at least according to the May 13, 1988 draft, which says the conversions are performed "as if by assignment".) However: 1) not all compilers *support* function prototypes, so unless you *never* expect to compile your code in an environment where the appropriate prototypes are not in scope, it's probably wise to put the explicit casts in anyway. 2) not all environments put the prototypes in the appropriate include files; see 1). 3) actual arguments that aren't matched by formal arguments in the prototype (i.e., if the prototype has a "..." in it) obviously can be converted only with the "default argument promotions", which obviously doesn't include converting 0 to a null pointer of the appropriate type. Doug was probably referring to one or more of those cases when he said: "Use of uncast NULL as an argument to a function is never correct usage ..." "Never" might, admittedly, be a little strong, if you take "correct" to mean "proper according to the pANS"; if you have extern void foo(char *ptr); in scope, a call foo(0); /* or foo(NULL); */ is correct - as long as you know for sure that in *every* environment in which this code will be compiled, the prototype in question will be in scope when "foo" is called.
throopw@xyzzy.UUCP (Wayne A. Throop) (02/25/89)
> cramer@optilink.UUCP (Clayton Cramer) > But the use of NULL when that's what > you mean will save someone some headaches when it comes time to > port a program to a segmented arguments. Not so. Because using uncast NULL as an actual argument for a formal argument of pointer type with no prototype in scope IS NEVER WHAT YOU MEAN. PERIOD. It is simply not portable to do this. The C lanuage as defined by K&R or (proposed) by ANSI does not guarantee the behavior if this is done. > Not true. In large model, stdio.h defines NULL to be 0L. NULL requires > no casting to work correctly with the Microsoft C compiler. In some models, sometimes. But in general, the usage is not portable to all memory models on this one compiler, and certainly not portable to all compilers. It is unsupported by any language standard (as opposed to partially supported by a language implementation). -- All things sick and cancerous, All evil great ans small, All things foul and dangerous, The Lord God made them all. --- Monty Python -- Wayne Throop <the-known-world>!mcnc!rti!xyzzy!throopw
throopw@xyzzy.UUCP (Wayne A. Throop) (02/25/89)
> cramer@optilink.UUCP (Clayton Cramer) > Microsoft C defines NULL in a way that works > for CORRECT calls in large model, and in medium and compact models. This is surely an unusual meaning of "correct". The C language makes it clear that passing an uncast arithmetic constant as an actual parameter to a formal parameter of type pointer when no prototype is in scope is never correct. -- Each nasty little hornet, Each beastly little squid, Who made the slimy urchin? Who make the shark? He did! --- Monty Python -- Wayne Throop <the-known-world>!mcnc!rti!xyzzy!throopw
throopw@xyzzy.UUCP (Wayne A. Throop) (02/25/89)
> heather@SEAS.UCLA.EDU > Why doesn't the C standard > treat NULL or 0 (a static/constant NULL or 0, i.e. indicated at compile time) > passed to a function that has a pointer value in the function prototype > as a special case and do the cast implicitly? Good point. The answer is that the discussion has been about what happens when there is no prototype in scope. It happens as you suggest when there is, but when there isn't, there isn't enough information to do the cast correctly. If the type of the formal argument is unknown to the compiler, even if the compiler was aware of NULL as a keyword, it would not know which type of null pointer was wanted. This is crucial for some architectures, where pointers to (or of) different types have different storage requiremnts or formats. -- God made integers. All else is the work of man. --- Leopold Kronecker (1823-1891) -- Wayne Throop <the-known-world>!mcnc!rti!xyzzy!throopw