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