[net.lang.c] Need some examples

craig@LOKI.ARPA (Craig Partridge) (07/30/85)

    I know this general subject has been hashed over before so please
respond to me directly, not to the whole net.  If I get enough
requests I'll post a summary.

    There are a variety of funny little problems with using the 0
pointer in C.  Recently I have gotten into a debate with a friend
about passing a 0 pointer to a function.  We agree that given
a function declaration like

f(ptr)
foo *ptr;
{
	[code]
}

calling f(0) is dangerous.  But my friend contends that calling
f() with a zero char pointer, e.g. f((char *)0), is safe, because
(char *) is the largest pointer, and that he doesn't know of a C
implementation that doesn't pass all pointers as the largest
possible pointer (ala the way floats always get passed as doubles).
I suspect the argument is wrong (and dangerous), but don't have
examples of machines on which this trick fails.  Anybody got
ammunition out there to help my side out?  (The question is not
just academic, it will affect a C standards document for a project).

Thanks,

Craig Partridge
craig@bbn-loki (ARPA)
craig%loki.arpa@csnet-relay (CSNET)
{decvax,ihnp4,wjh12}!bbncca!craig (USENET)

gwyn@brl-tgr.ARPA (Doug Gwyn <gwyn>) (07/31/85)

>     There are a variety of funny little problems with using the 0
> pointer in C.

There is no "the" 0 pointer.  There are an infinite variety of null
pointers, and only in certain contexts (e.g., comparison against 0
integer constant) is one permitted to pretend otherwise.  This
subject is discussed in this newsgroup every few months.

> calling f(0) is dangerous.  But my friend contends that calling
> f() with a zero char pointer, e.g. f((char *)0), is safe, because
> (char *) is the largest pointer, and that he doesn't know of a C
> implementation that doesn't pass all pointers as the largest
> possible pointer (ala the way floats always get passed as doubles).

"Ignorance is no excuse."

> I suspect the argument is wrong (and dangerous), but don't have
> examples of machines on which this trick fails.  Anybody got
> ammunition out there to help my side out?

Any "trick" whose working is not guaranteed by the language
definition should not be relied upon!  Your organization seems to
have a real problem with people giving bogus advice.  Why in the
world would anyone WANT to formalize such a "trick"?

You should not need an actual implementation example.  I will give
a hypothetic example, though.  Perhaps some real implementation is
like this, perhaps not; the fact that it is permitted should rule
out using the "trick", which will not work in this case.  There are
also other possible ways that the "trick" could fail, including the
use of tagged architectures, non-zero bit patterns for null
pointers, and so on.

EXAMPLE:

Consider a 16-bit word-addressed architecture (e.g., CDC 1700,
H-316, perhaps DG Nova).  It is possible to represent any (int *)
in a single word, but it takes 2 words to represent a (char *).
Consider the function
	void foo( int a, int *b, int c );
Suppose that for economy's sake (very important on 16-bit machines)
the stack size of a function parameter is the minimum number of
words needed to hold it (1 word for each of the 3 parameters in this
example).  Now, suppose one invokes the function as
	foo( 1, (char *)0, 3 );
Because of the parameter layout, either the first or the third
parameter will not be transmitted correctly (it will have part
of the (char *) in its place on the stack frame).  QED.

rosalia@tekig4.UUCP (Mark Galassi) (08/06/85)

In article <299@brl-tgr.ARPA> you write:
>
>    There are a variety of funny little problems with using the 0
>pointer in C.  Recently I have gotten into a debate with a friend
>about passing a 0 pointer to a function.  We agree that given
>a function declaration like
>
>f(ptr)
>foo *ptr;
>{
>	[code]
>}
>
>calling f(0) is dangerous.  But my friend contends that calling
>f() with a zero char pointer, e.g. f((char *)0), is safe, because
>(char *) is the largest pointer, and that he doesn't know of a C
>implementation that doesn't pass all pointers as the largest
>possible pointer (ala the way floats always get passed as doubles).

    There is a problem: when you work with the Intel 80286
in large models instead of small ones **(for those who have never
worked with this misfit of nature, the 80286 cannot use more than
64K of memory unless you do some bank switching, which is such a pain
in the neck that one usually tries to use the small model of program
in which you only make use of 64K)**, you have to be careful because
pointers are 32 bits in large model, and 16 bits in small model.
    This is a horrible situation because you cannot even trust to
do "#define NULL 0L", because that will not work in small model
and you will have garbage on the stack. On the other hand
"#define NULL 0" will not work for the large model. The only
solution is to cast things properly with (char *), but then
you have to compile all your libraries twice, once with the large
model C compiler and once with the small one.
    So much for that, and the chains of the past (4004) weigh
heavilly upon us programmers, while the salesmen are always happy
to talk about how the segments "enable portability of software".

				Mark Galassi
			...!tektronix!tekig4!rosalia
			...!tektronix!reed!rosalia