use of NULL
T. William Wells
bill at twwells.uucp
Sun Feb 19 05:23:37 AEST 1989
In article <965 at optilink.UUCP> cramer at 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
More information about the Comp.lang.c
mailing list