[comp.lang.c] Query: Implementation with non-zero NULL

henry@delftcc.UUCP (05/28/87)

I'm writing a book on C portability.  Interested to find actual
implementation of C where the null pointer is not "all bits zero."

In such an implementation, does
	char *p; p = (char *)0;
result in p having the special null value?  How is NULL defined?

Are static pointers initialized to all bits zero or to the null value
(as in ANSI spec)?

In such an implementation, can you use the conventional abbreviation
	if (p)
to mean
	if (p != NULL)

guy%gorodish@Sun.COM (Guy Harris) (05/29/87)

> I'm writing a book on C portability.  Interested to find actual
> implementation of C where the null pointer is not "all bits zero."

Try looking for a machine with lots of instruction-set features for
type checking *et al*; such a machine might have some special format
for a null pointer.

> (List of questions about the implementation)

One hopes that the implementation will do the "right thing" in all
those cases.  This does not guarantee that there is not an
implementation that does the wrong thing, it just means that if there
is such an implementation, it has bugs in it and should be fixed, and
that the implementer has no leg to stand on if they want to defend
the implementation.  *I* certainly don't intend to alter my code on
the off chance that somebody who didn't understand C did the
implementation; were I to come across such an implementation, I would
inform them that their implementation was broken.

BTW,

	char *p; p = 0;

will also result in assigning a null pointer to "p" on a correct
implementation.
	Guy Harris
	{ihnp4, decvax, seismo, decwrl, ...}!sun!guy
	guy@sun.com

garry@batcomputer.tn.cornell.edu (Garry Wiegand) (05/30/87)

In a recent article henry@delftcc.UUCP (Henry Rabinowitz) wrote:
>I'm writing a book on C portability.  Interested to find actual
>implementation of C where the null pointer is not "all bits zero."

And I'd be interested in knowing what difference it could ever make
to a portable program:  the only ways I know to look at the bits
is to union the pointer with an integer (and load the pointer &
look at the integer), or to cast the pointer to an integer. Both of which 
would be very forbidden in portable code.

>Are static pointers initialized to all bits zero or to the null value
>(as in ANSI spec)?

You should NEVER assume a not-explicitly-initialized static variable
is given any particular value by anybody.

Note: I have not yet seen a compiler written to the ANSI spec. Talking
about porting between ANSI-spec compilers is not a very interesting 
thing to do, and won't be for a while (five years, maybe?)

>In such an implementation, can you use the conventional abbreviation
>	if (p)
>to mean
>	if (p != NULL)

Um, might I suggest that this book project is not really a good idea for
you? And the world?  (Please see K&R on the meaning of 'if(p)').

garry wiegand   (garry@oak.cadif.cornell.edu - ARPA)
		(garry@crnlthry - BITNET)

afg@gass.UUCP (05/31/87)

I believe that the recently released Honeywell Multics C compiler 
implements NULL pointers with a non-zero value.  This is because there
is a reserved pointer value in the Multics architecture which the
hardware will generate a special "null pointer fault" for, when someone
tries to go indirect through it.

Send me mail if you want more information.

Andrew Ginter, Ginter and Associates, 208 - 21 Avenue NW, Calgary, Alberta
(403) 230-3012            ...!{ubc-vision, ihnp4}!alberta!calgary!gass!afg

gwyn@brl-smoke.ARPA (Doug Gwyn ) (05/31/87)

In article <1217@batcomputer.tn.cornell.edu> garry@oak.cadif.cornell.edu writes:
>Note: I have not yet seen a compiler written to the ANSI spec. Talking
>about porting between ANSI-spec compilers is not a very interesting 
>thing to do, and won't be for a while (five years, maybe?)

I don't know how you come up with "five years".  We're hoping to have
an official standard in considerably less than a year, and many C
compiler vendors will have ANSI-compliant implementations available
almost immediately after that (a few months, perhaps).  So this will
be an important issue in well under two years.

john@viper.Lynx.MN.ORG (John Stanley) (06/01/87)

In article <158@delftcc.UUCP> henry@delftcc.UUCP (Henry Rabinowitz) writes:
 >
 >Are static pointers initialized to all bits zero or to the null value
 >(as in ANSI spec)?
 >

  If, you're refering to an initialized static, it's whatever you
specify.  If, on the other hand, you're refering to an UN-initialized
static pointer, the answer is a resounding "Neither!"....  An un-
initialized variable is just that.  It can initialy hold literaly
-any- value that variable can possibly hold.  You should never assume
anything about any variable until you've set it.

  If, as you stated, you're writing a book on portability, you should
mention that neither of the alternatives you mention is guarenteed.
If the programmer wants anything, including null pointers -or- null
bits, in a pointer, the value -MUST- be explicitly defined.  I've
written code for more than one system where if you don't specify
the value, you get whatever was there before you.  

  The ANSI standard may specify something as a default, but if you
really expect to make your code portable you really need to explicitly 
tell the compiler what it's suppost to be doing.  That way you don't 
get as many unpleasant surprises when you try porting to another 
system...



  If, on the other hand, I've missed the point you were getting at..
"Oh really?  (long pause)  Nevermind...."

--- 
John Stanley (john@viper.UUCP)
Software Consultant - DynaSoft Systems
UUCP: ...{amdahl,ihnp4,rutgers}!{meccts,dayton}!viper!john

m5@bobkat.UUCP (06/01/87)

In article <1217@batcomputer.tn.cornell.edu> garry@oak.cadif.cornell.edu writes:
>>Are static pointers initialized to all bits zero or to the null value
>>(as in ANSI spec)?
>
>You should NEVER assume a not-explicitly-initialized static variable
>is given any particular value by anybody.

I thought that static stuff is supposed to be initialized to zero.  Have
I been confused all these years?

I do agree that depending on thusly NULLed pointers is wombly.



-- 
Mike McNally, mercifully employed at Digital Lynx ---
    Where Plano Road the Mighty Flood of Forest Lane doth meet,
    And Garland fair, whose perfumed air flows soft about my feet...
uucp: {texsun,killer,infotel}!pollux!bobkat!m5 (214) 238-7474

jfh@killer.UUCP (06/01/87)

In article <1217@batcomputer.tn.cornell.edu>, garry@batcomputer.tn.cornell.edu (Garry Wiegand) writes:
> In a recent article henry@delftcc.UUCP (Henry Rabinowitz) wrote:
> >I'm writing a book on C portability.  Interested to find actual
> >implementation of C where the null pointer is not "all bits zero."
> 
> And I'd be interested in knowing what difference it could ever make
> to a portable program:  the only ways I know to look at the bits
> is to union the pointer with an integer (and load the pointer &
> look at the integer), or to cast the pointer to an integer. Both of which 
> would be very forbidden in portable code.

I don't know, I find myself looking at bits from time to time and not
even realizing that I am doing myself in, ANSI Standard-wise.  As far
as forbidding casting a pointer to an integer in portable code, I would
think that only the programmer must justify whether or not the cast
is needed.  Casts are permitted, I think your statement should be
'Both of which should be explicitly declared and well documented.'

> >Are static pointers initialized to all bits zero or to the null value
> >(as in ANSI spec)?
> 
> You should NEVER assume a not-explicitly-initialized static variable
> is given any particular value by anybody.

( low burner on - :-)
And you should read some of the documentation on the language.  I'm not
sure who wrote this version of the C Language reference, but I have seen
it included in other vendors manuals.  In the Plexus Sys5 Unix Programmer's
Guide, section 2.7.7 it says (and I quote)

	"Static and external variables that are not initialized are
	guaranteed to start off at zero.  Automatic and register variables
	that are not initialized are guaranteed to start off as garbage."

I have seen this before in papers written by the Gods Of Unix ...  Sounds
like you been usin' too much Pascal ... :-) :-) :-)

( low burner off - :-)

> Note: I have not yet seen a compiler written to the ANSI spec. Talking
> about porting between ANSI-spec compilers is not a very interesting 
> thing to do, and won't be for a while (five years, maybe?)

Well, of course not.  They haven't figured the darn thing out yet.  But,
not writing to the ANSI spec is going to give you alot of work to do
when your vendor sends out the new ANSI compiler and all your programs
don't conform.

> 
> >In such an implementation, can you use the conventional abbreviation
> >	if (p)
> >to mean
> >	if (p != NULL)
> 
> Um, might I suggest that this book project is not really a good idea for
> you? And the world?  (Please see K&R on the meaning of 'if(p)').
> 
> garry wiegand   (garry@oak.cadif.cornell.edu - ARPA)
> 		(garry@crnlthry - BITNET)

Um, Garry, might I suggest that he asked a good question and that you
get a personality.  Yes, I think the statements

	if (p)
and
	if (p != NULL) /* where NULL is not (char *) 0 */
could cause us all alot of trouble.

- John.

Disclaimer -
	No disclaimer.  Whatcha gonna do, sue me?

mlandau@Diamond.BBN.COM (Matt Landau) (06/01/87)

In comp.lang.c (<1070@viper.Lynx.MN.ORG>), john@viper.UUCP (John Stanley) writes:
>In article <158@delftcc.UUCP> henry@delftcc.UUCP (Henry Rabinowitz) writes:
> >
> >Are static pointers initialized to all bits zero or to the null value
> >(as in ANSI spec)?
> >
>
>  If, you're refering to an initialized static, it's whatever you
>specify.  If, on the other hand, you're refering to an UN-initialized
>static pointer, the answer is a resounding "Neither!"....  An un-
>initialized variable is just that.  It can initialy hold literaly
>-any- value that variable can possibly hold.  You should never assume
>anything about any variable until you've set it.

Once more, with feeling:  STATIC VARIABLES THAT ARE NOT EXPLICITLY 
INITIALIZED ARE INITIALIZED TO ZERO BY DEFAULT.

Take a look at the C Reference Manual, section 8.6, paragraph 3, which
you should find on page 198 of the venerable K&R.  It says this:

	Static and external variables which are not initialized
	are guaranteed to start off as 0; automatic and register
	variables which are not initialized are guaranteed to
	start off as garbage.

The November 1985 draft proposed ANSI standard for C (section C.5.6) says
this about the subject:

	An object that has static storage duration may be initialized
	by constant expressions only.  If such an object is not
	initialized explicitly, it is initialized implicitly as if 
	every scaler member were assigned the integer constant zero.

More recent versions of dpANS may have changed the wording, but the behavior
is deeply embedded in the definition of the C programming language.

My apologies for going on at such length about such an obvious point, but 
this is the third time and the last few days that I've seen someone in
comp.lang.c claim that *static* variables aren't initialized to anything.
-- 
 Matt Landau			    "Waiting for a flash of enlightenment
 mlandau@diamond.bbn.com	     in all this blood and thunder..."

allen@gitpyr.gatech.EDU (P. Allen Jensen) (06/01/87)

In article <158@delftcc.UUCP>, henry@delftcc.UUCP (Henry Rabinowitz) writes:
> In such an implementation, does
> 	char *p; p = (char *)0;
> result in p having the special null value?  How is NULL defined?
> 
> Are static pointers initialized to all bits zero or to the null value
> (as in ANSI spec)?
> 
> In such an implementation, can you use the conventional abbreviation
> 	if (p)
> to mean
> 	if (p != NULL)


On the PRIME system under PRIMIX, there is a special "undefined pointer"
value.  This value is used by the procedure call mechanism when fewer
arguments are passed to a subroutine by reference (ie FORTRAN) than
are expected.  Because of this, constructs such as the

       if(p)

Do not yield correct results.  The prime also has modes of operation in which
pointers are 48 bits even though long, int and float are all 32 bits.
This is a hold-over from the segmented addressing of the older 16 bit primes.

The value of NULL is 0x60000000 on a prime.

P. Allen Jensen

allen@gitpyr.gatech.EDU (P. Allen Jensen) (06/01/87)

In article <3673@gitpyr.gatech.EDU>, allen@gitpyr.gatech.EDU (P. Allen Jensen) writes:
> are expected.  Because of this, constructs such as the
>        if(p)
> Do not yield correct results.  The prime also has modes of operation in which
> pointers are 48 bits even though long, int and float are all 32 bits.
> This is a hold-over from the segmented addressing of the older 16 bit primes.
> The value of NULL is 0x60000000 on a prime.
> 
> P. Allen Jensen

Correction - if(p) yields  false if p = (char *) NULL
Also, if(p != 0) also yields false.  The 0 is cast to (char *).

The value of 0x60000000 is correct.  If you do a union with a long and compare
the long with zero (0), they will not be equal.  Also, since in some modes
a pointer may be 48 bits, you would only get the first 32 bits in the union.

P. Allen Jensen

guy%gorodish@Sun.COM (Guy Harris) (06/02/87)

> On the PRIME system under PRIMIX, there is a special "undefined pointer"
> value.  This value is used by the procedure call mechanism when fewer
> arguments are passed to a subroutine by reference (ie FORTRAN) than
> are expected.  Because of this, constructs such as the
> 
>        if(p)
> 
> Do not yield correct results.

Translation: PRIME has no implementation of C on their machines.  If
the construct

	if (p)

where "p" is a pointer does not compare "p" with the undefined
pointer value, then the language being implemented isn't C.
Furthermore, the clauses

	if (p)

	if (p != NULL)

	if (p != 0)

	if (p != (whatever_p_points_to *)0)

	if (p != (whatever_p_points_to *)NULL)

all have the same meaning in C, so they must all compile to
equivalent code.

It may seem counter-intuitive that the statement

	if (p)

compare the bit pattern stored in "p" with a bit pattern other than
all-zeroes, but that's just too bad - that's the way C works.  One
would hope any C implementor would be sufficiently aware of the way C
works to avoid naively generating a test against 0 for this
construct; if, in fact, the PRIME C compiler does generate such a
test, I guess there are C implementors out there too naive to
properly implement C.

Are you certain that that construct doesn't yield a correct result
(e.g., compares "p" with an all-zero bit pattern), or are you just
assuming this?

> The value of NULL is 0x60000000 on a prime.

If you mean that things like <stdio.h> contain

	#define	NULL	0x60000000

then this confirms that they didn't implement C.
	Guy Harris
	{ihnp4, decvax, seismo, decwrl, ...}!sun!guy
	guy@sun.com

g-rh@cca.CCA.COM (Richard Harter) (06/02/87)

In article <3673@gitpyr.gatech.EDU> allen@gitpyr.gatech.EDU (P. Allen Jensen) writes:
>In article <158@delftcc.UUCP>, henry@delftcc.UUCP (Henry Rabinowitz) writes:
>> In such an implementation, does
>> 	char *p; p = (char *)0;
>> result in p having the special null value?  How is NULL defined?
>> 
>> Are static pointers initialized to all bits zero or to the null value
>> (as in ANSI spec)?
>> 
>> In such an implementation, can you use the conventional abbreviation
>> 	if (p)
>> to mean
>> 	if (p != NULL)
>
>
>On the PRIME system under PRIMIX, there is a special "undefined pointer"
>value.  This value is used by the procedure call mechanism when fewer
>arguments are passed to a subroutine by reference (ie FORTRAN) than
>are expected.  Because of this, constructs such as the
>
>       if(p)
>
>Do not yield correct results.  The prime also has modes of operation in which
>pointers are 48 bits even though long, int and float are all 32 bits.
>This is a hold-over from the segmented addressing of the older 16 bit primes.
>
	I don't believe this is quite correct.  Our software is written in
C and runs under UNIX, VMS, and PRIMOS, so we get to get bitten by a lot of
these things.  (Other than tests we don't run under PRIMIX, since I'm not
so young as I used to be, and I'm always afraid that I won't be around when
the output shows up.)  The if(p) construct is supposed to work by definition
of the C language, and it does, if p is null.  Accessing an undefined pointer
in C will cause a system trap.

	As of the 19.4 C compiler all pointers are 48 bits.  In versions of C
prior to 19.4, char pointers were 48 bits and short, int, and long were 32
bits (don't know about structs).  As you may imagine, code which is sloppy
about pointers doesn't port too well to the Prime.  Generally speaking, if
your code is lint-clean you won't have portability problems with pointers.

	The big bugaboo in porting to the Prime is that they have messed
with the standard C library (under PRIMOS).  Argument sequences are changed
in some cases, and the older manuals were flatly wrong in places.  As a
practical matter, programs which do not isolate file opens and closes will
be a mess to port.

	Another difference which can dramatically impact portability is that
PRIME uses '8 bit ascii'.  What this means is that the high order bit is 
turned on in all character data.  If you use 0xa instead of '\n' you are
in for an unpleasant surprise.

	Still another trap for the naive UNIX C programmer is that stream
files (which are called SAM files under PRIMOS) are stored with an automatic
compression mode in which a tab character signals that the next byte is a
count byte giving the number of blanks that the pair is to be replaced with.
If you create a file with fopen/fprintf/fclose and then go back and read it
with open/read/close you are in for another little surprise.


>The value of NULL is 0x60000000 on a prime.
>
>P. Allen Jensen


-- 

Richard Harter, SMDS Inc. [Disclaimers not permitted by company policy.]

chris@mimsy.UUCP (Chris Torek) (06/02/87)

In article <1070@viper.Lynx.MN.ORG> john@viper.Lynx.MN.ORG (John
Stanley) writes:
>  If, you're refering to an initialized static, it's whatever you
>specify.  If, on the other hand, you're refering to an UN-initialized
>static pointer, the answer is a resounding "Neither!"....  An un-
>initialized variable is just that.

Wrong.  See K&R, p. 198.  Similar (but no doubt more precise)
wording can be found in H&S and in the dpANS.  Unitialised static
pointers must contain NULL, or the implementation is broken [1].
Automatic variables, including registers, that are not initialised
contain trash; the trash may be machine dependent, as on, e.g.,
4BSD Vaxen, where new stack pages are zero filled.

----
[1] Except static unions, where it may be impossible to have all
union members start off as zero or NULL, since zero and NULL may
differ (and indeed, zero and zero may differ, e.g., floating zero
versus integer zero).

-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7690)
Domain:	chris@mimsy.umd.edu	Path:	seismo!mimsy!chris

chris@mimsy.UUCP (Chris Torek) (06/02/87)

In article <3673@gitpyr.gatech.EDU> allen@gitpyr.gatech.EDU (P. Allen
Jensen) writes:
>On the PRIME system under PRIMIX, there is a special "undefined pointer"
>value. ... Because of this, constructs such as the
>
>	if(p)
>
>do not yield correct results.

Then the PRIMIX compiler is broken.  See K&R, p. 201.  (This does not,
of course, help those who must use the broken compiler.)

>The value of NULL is 0x60000000 on a prime.

If NULL is `#define'd as 0x60000000, the compiler is even more
broken.  Given this special nil pointer format, and assuming that
the union below gets at the proper portion of a pointer, the program
below should print only `right's:

	#include <stdio.h>
	#define	magic	0x60000000

	/*ARGSUSED*/
	main(argc, argv)
		int argc;
		char **argv;
	{
		union {
			long	l;
			int	*p;
		} u;
		static char r[] = "right\n";
		static char w[] = "wrong\n";

		u.p = 0;
		printf(u.l == magic ? r : w);
		printf(u.p == NULL ? r : w);
		printf(u.p ? w : r);
		exit(0);
	}

The compiler is required to transform any integer constant zero in
any pointer context into the appropriately typed nil pointer.  In
the expressions `if (p) s1; else s2;' and `p ? e1 : e2', where p
is a pointer, p is being implicitly compared to a constant zero;
if p is not equal to the nil pointer resulting from this transformation,
the compiler should evaluate the `true' branch or expression, s1
or e1; otherwise, it should evaluate the `false' branch or expression,
s2 or e2.  If the compiler does something else, it is broken.

Given these conversion rules, the only correct ways to define NULL
are

	#define NULL 0

and

	#define NULL 0L		/* or 0l, or ((long)0) */

The latter is unnecessary and potentially troublesome.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7690)
Domain:	chris@mimsy.umd.edu	Path:	seismo!mimsy!chris

guy@gorodish.UUCP (06/02/87)

> Correction - if(p) yields  false if p = (char *) NULL

In other words, constructs like

	if (p)

*do* yield correct results, and PRIME's C implementation *is*
correct.  (Assuming that "if (!p)" yields *true* if is a null
pointer.)  BIG difference!

> Also, if(p != 0) also yields false.

In other words, "if (p)" and "if (p != 0)" (and "if (p != NULL)")
*are* the same.  This is as it should be; those three constructs mean
the same thing in C, and should all yield true iff "p" is not a null
pointer.

> The 0 is cast to (char *).

Actually, the 0 is *coerced* to (char *); it is only *cast* to "char *"
if you write "(char *)0".  Casting is one way of generating a
coercion, but it isn't the only way.  In this case, the compiler
knows that one operand of the "==" is a pointer, and the other is a
constant 0, so it knows that it must coerce the constant 0 to a null
pointer value of the appropriate type; no cast is necessary.

> The value of 0x60000000 is correct.  If you do a union with a long and
> compare the long with zero (0), they will not be equal.  Also, since in
> some modes a pointer may be 48 bits, you would only get the first 32 bits
> in the union.

I presume "the value of 0x60000000 is correct" means "that is the bit
pattern stuffed into a null pointer", not "NULL is #defined to be
0x60000000".

Both of the behaviors you describe are perfectly legitimate, and
permissible in a C implementation.
	Guy Harris
	{ihnp4, decvax, seismo, decwrl, ...}!sun!guy
	guy@sun.com

harry@rainy.UUCP (06/02/87)

At rev 20.2.2 of Primos (and 2.0 of Primix) a NULL pointer has a
value of 0.  Also, pointers are now 32 bits long.  However, sloppy
C code still does not work because pointer arithmetic is different
than integer arithmetic.

The 32 bit C pointers on Prime are actually similar to Prime's 32
bit word pointers (one word is 16 bits).  The structure of the pointer
is as follows (with bit 0 being the lsb)

  bits 31       - Fault bit (1 => point fault is generated when this
                             address is used)
       30 - 29  - Ring bits
       28       - 0 => left byte of word
                  1 => right byte of word
       27 - 16  - segment number
       15 -  0  - word number

As you can see, if you treat a pointer as an integer and add 1, you
increment it one word (two bytes).  However, if it remains a pointer,
the Prime will do the pointer arithmetic correctly.

The other comments about I/O are correct.  Prime stores ASCII files with
the high order bit on for each byte.  In addition, blanks are compressed
(a byte of 220 (octal) followed a byte indicating the number of blanks).
Finally lines in Prime ASCII files end with a 212 (octal) and are padded
with a null is the line terminates in the middle of a word.  The stdio
is supposed to expand this automatically when reading if you tell it to.
However, it is not bug free in Primix.  For example, if you size an ASCII file
using stat, open it and read to the end, and then size is again before closing,
you end up with TWO different sizes for the same file :-(

In general, working with Primix is a pain in the neck.  The C compiler is
okay, but the preprocessor cannot handle the "defined(A)" construct!
Working with a real Unix machine is much easier!
-- 
Harry Edmon                   UUCP:   harry@erbe.geo.washington.edu or
(206) 543-0547                        uw-beaver!geops!rainy!harry
Department of Atmospheric Sciences
University of Washington        BITNET: 24440@UWACDC

blarson@castor.usc.edu.UUCP (06/02/87)

(In case you missed a few articles, the original poster was incorrect, Prime
C does handle if(p), where p is a pointer, correctly.  NULL is #defined to 0.
The bit pattern used by a NULL pointer does not matter to correct code.)

In article <16314@cca.CCA.COM> g-rh@CCA.CCA.COM.UUCP (Richard Harter) writes:
>	As of the 19.4 C compiler all pointers are 48 bits.  In versions of C
>prior to 19.4, char pointers were 48 bits and short, int, and long were 32
>bits (don't know about structs).  As you may imagine, code which is sloppy
>about pointers doesn't port too well to the Prime.  Generally speaking, if
>your code is lint-clean you won't have portability problems with pointers.

As far as I know, all versions of prime C allocate 48 bits for pointers in
64v mode.  (19.2 was the first I used.)  Of course, only the first 32 bits
are significant on non-char pointers.  32ix mode, as supported by C 19.4-5.0,
uses 32 bit pointers.  (For those not experienced on primes, they support
several instruction sets.  64v and 32i(x) are the two most modern.)
Isn't sloppy code ALWAYS hard to port?

>	The big bugaboo in porting to the Prime is that they have messed
>with the standard C library (under PRIMOS).  Argument sequences are changed
>in some cases, and the older manuals were flatly wrong in places.  As a
>practical matter, programs which do not isolate file opens and closes will
>be a mess to port.

I don't ever remember having problems with this on routines that
consistant meaning between implemintations.  Can you give examples of
a standard routine that prime has messed up? 

My biggest problems have been with bugs.  Does prime test their C
compiler on real programs?

>	Another difference which can dramatically impact portability is that
>PRIME uses '8 bit ascii'.  What this means is that the high order bit is 
>turned on in all character data.  If you use 0xa instead of '\n' you are
>in for an unpleasant surprise.

Yup.  Of course, there is a compiler option not to do this, as long as you
make sure and set the high bit on any characters sent to the library routines
yourself.

>	Still another trap for the naive UNIX C programmer is that stream
>files (which are called SAM files under PRIMOS) are stored with an automatic
>compression mode in which a tab character signals that the next byte is a
>count byte giving the number of blanks that the pair is to be replaced with.
>If you create a file with fopen/fprintf/fclose and then go back and read it
>with open/read/close you are in for another little surprise.

^Q is the character used for space compression, not tab.  Also, you forgot
about the null that follows a LF if needed to make the line an even number
of characters, and that most primos programs will ignore any trailing spaces.
Also, Prime C defaults to creating DAM files, not SAM files.

>>The value of NULL is 0x60000000 on a prime.

If you are going to publish the bit pattern, you should explain what
the bits mean.  This is a ring 3 (user mode) pointer to segment 0
address 0.  The other 16 bits you missed don't matter since the extend bit
isn't set.  Other primos languages use an address of segment (octal)
7777 address 0.
-- 
Bob Larson
Arpa: Blarson@Usc-Ecl.Arpa
Uucp: (several backbone sites)!sdcrdcf!usc-oberon!castor.usc.edu!blarson
			seismo!cit-vax!usc-oberon!castor.usc.edu!blarson

marv@ism780.UUCP (06/03/87)

>  If, you're refering to an initialized static, it's whatever you
>specify.  If, on the other hand, you're refering to an UN-initialized
>static pointer, the answer is a resounding "Neither!"....  An un-
>initialized variable is just that.  It can initialy hold literaly
>-any- value that variable can possibly hold.  You should never assume
>anything about any variable until you've set it.
>John Stanley (john@viper.UUCP)
>Software Consultant - DynaSoft Systems
>UUCP: ...{amdahl,ihnp4,rutgers}!{meccts,dayton}!viper!john

K&R does not seem to agree with the above. On page 198 one reads:

   "Static and external variables which are not initialized are
   guaranteed to start off as 0: automatic and register variables
   which are not initialized are guaranteed to start of as garbage."

Note that the ascii character '0' appearing in a C source program has a
context dependent meaning.  It can represent either the integer constant
that falls between -1 and +1 or it can represent a constant pointer that
points to no object.  With this in mind I take the above quote to mean that
all uninitalized (static or external) variables that are numbers will start
out with the value zero and all uninitialized variables that are pointers
start out pointing to no object.  I believe this is all inclusive since the
only primative types in C are pointers and numbers (with various ranges and
scalings).

      Marv Rubinstein -- Interactive Systems

dave@sds.UUCP (06/03/87)

In article <3673@gitpyr.gatech.EDU>, allen@gitpyr.gatech.EDU (P. Allen Jensen) writes:
> [...] The prime also has modes of operation in which
> pointers are 48 bits even though long, int and float are all 32 bits.

I thought the C language guaranteed that there was an integral type
large enough to hold any pointer type.  From p. 210 of the Apocrypha
(== Appendix A of K&R :-)
	
	A pointer may be converted to any of the integral types
	large enough to hold it.  Whether an int or long is
	required is machine dependent.

Although the word "guarantee" doesn't appear here (as it does elsewhere),
the second sentence seems to disallow the first sentence from being
vacuously true.


Dave Schmidt

Quote for the day:
	"The superiorly armed force must win in battle."  - G. Custer

dave@murphy.UUCP (06/03/87)

In article <1217@batcomputer.tn.cornell.edu>, garry@batcomputer.tn.cornell.edu (Garry Wiegand) writes:
> You should NEVER assume a not-explicitly-initialized static variable
> is given any particular value by anybody.

K&R says, on p. 198, about halfway down: "Static and external variables
which are not initialized are guaranteed to start off as 0."  The ANSI
draft that I have (admittedly an old one, July 1985) says, in section
C.5.6, p.51: "If such an object [static object] is not initialized
explicitly, it is initialized implicitly as if every scalar member were
assigned the integer constant 0."

In most virtual-memory environments, this is done by the OS zeroing out the
allocated memory for security reasons.  The only place where it might
cause problems is in zeroing out static pointers or floating types, where
the bit pattern that means zero might not be the all-zeroes pattern.
---
"Country beats the hell out of me" -- Jerry Dale McFadden

Dave Cornutt, Gould Computer Systems, Ft. Lauderdale, FL
[Ignore header, mail to these addresses]
UUCP:  ...!{sun,pur-ee,brl-bmd,seismo,bcopen,rb-dc1}!gould!dcornutt
 or ...!{ucf-cs,allegra,codas,hcx1}!novavax!gould!dcornutt
ARPA: dcornutt@gswd-vms.arpa

"The opinions expressed herein are not necessarily those of my employer,
not necessarily mine, and probably not necessary."

john@viper.UUCP (06/03/87)

In article <6873@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes:
 >
 >Wrong.  See K&R, p. 198.  Similar (but no doubt more precise)
 >wording can be found in H&S and in the dpANS.  Unitialised static
 >pointers must contain NULL, or the implementation is broken [1].
 >Automatic variables, including registers, that are not initialised
 >contain trash; the trash may be machine dependent, as on, e.g.,
 >4BSD Vaxen, where new stack pages are zero filled.
 >

  The message I was replying to was discussing points relating to
common problems/pitfalls in writing portable code.  From this it
should be obvious that "what K&R says" is not as relevent as "what
have people encountered in real life".  With all due respect to
Chris and K&R, what I was (poorly) trying to say was, that when
trying to write portable code, you should never use a variable
before it's been explicitly initialized.  This may seem irrelevant
to you, but it may be significant to someone else trying to write
or port code to a system/compiler where the strict word-of-K&R
may not have been fully implemented.  

  What's that you say?  No program would ever fail to run on your
system because someone used a "feature" defined in K&R that didn't 
work that way on your system?  Mind telling me what you've been 
smoking and where I can get some?  :-)  :-)  :-)

--- 
John Stanley (john@viper.UUCP)
Software Consultant - DynaSoft Systems
UUCP: ...{amdahl,ihnp4,rutgers}!{meccts,dayton}!viper!john

jfh@killer.UUCP (06/04/87)

In article <20130@sun.uucp>, guy%gorodish@Sun.COM (Guy Harris) writes:
[ along with someone else whose name got trashed at some point in the games ]
> > On the PRIME system under PRIMIX, there is a special "undefined pointer"
> > value.  This value is used by the procedure call mechanism when fewer
> > arguments are passed to a subroutine by reference (ie FORTRAN) than
> > are expected.  Because of this, constructs such as the
> > 
> >        if(p)
> > 
> > Do not yield correct results.
> 
> Translation: PRIME has no implementation of C on their machines.  If
> the construct
> 
> 	if (p)
> 
> where "p" is a pointer does not compare "p" with the undefined
> pointer value, then the language being implemented isn't C.

Now for my two cents worth.  Seven years later, my K&R is still at the
bookstore waiting to be bought, so I can't quote from the Holy Bible
according to K&R.

From the current edition of the C Language (out of the Plexus Programmer's
Guide) I quote:

2.6.7 - Equality Operators

	"A pointer may be compared to an integer only if the integer
	is the constant 0.  A pointer to which 0 has been assigned
	is guaranteed not to point to any object and will appear to
	be equal to 0.  In conventional usage, such a pointer is
	considered to be null."

2.7.7, pp 3 - Initialization

	"Static and external variables that are not initialized are
	guaranteed to start off at zero. ..."

				-- Plexus Sys5 Programmer's Guide

From 2.6.7 it appears Guy is correct (references, documentation - I keep
asking but no one listens ... :-(, 0 and (char *) 0 are identical when
used in the comparision in the posting.  From 2.7.7 we see that even
static and external variables are nulled.  (The ANSI standard says it
much better.)

If your standard I/O declares NULL == 0x(something other than zero) and
then expects it to work, you are doomed to eternal buggyness.

- John.

Senior Systems Analyst		Disclaimer:  I didn't do it.  Honest.
HECI Exploration Co, Inc.	UUCP: { backbone } ! killer!jfh
Dallas, Republic of Texas

"If you don't own an oil well, buy one".

jimp@cognos.uucp (Jim Patterson) (06/04/87)

In article <1070@viper.Lynx.MN.ORG> john@viper.UUCP (John Stanley) writes:
>In article <158@delftcc.UUCP> henry@delftcc.UUCP (Henry Rabinowitz) writes:
> >
> >Are static pointers initialized to all bits zero or to the null value
> >(as in ANSI spec)?
>
>  If, you're refering to an initialized static, it's whatever you
>specify.  If, on the other hand, you're refering to an UN-initialized
>static pointer, the answer is a resounding "Neither!"....  

I won't deny that there may be some (non-conforming) C compilers that
don't always initialize statics, or that in some environments it's
costly to require that they be initialized, but it's quite clear in
both K&R and in the ANSI C draft that ALL statics be initialized.

Kierneghan & Ritchie, in "The C Programming Language", 1978
(generally regarded as the definitive specification of the C
language prior to ANSI's involvement) state in section 4.9 (page 82)
that "In the absence of explicit initialization, external and static
variables are guaranteed to be initialized to 0".  Section 8.6 of
the reference manual (page 198) back this up; "Static and external
variables which are not initialized are guaranteed to start off as 0".

ANSI C has maintained this guarantee; in section 3.7.2 of the May
15, 1987 draft (page 73) an object defined outside of a function of
either static or with no storage class specifier and no initializer
is termed a "tentative definition". The section goes on to state "If
no subsequent definition is encountered, the first tentative
definition is taken to be a definition with initializer equal to 0".

That, however, doesn't answer Mr. Rabinowitz's question. There is some
additional clarification in the ANSI draft (this time from July 6, 1986;
I'm afraid I don't have a more current copy of the relevant pages).
This is in section 3.5.6 on Initialization (page 61):

  "If an object that has static storage duration is not initialized
  explicitly, it is initialized implicitly as if every member
  that has arithmetic type were assigned 0 and every member that has 
  pointer type were assigned a null pointer constant".

(If someone has a more up to date complete copy of the draft, perhaps
you could confirm if this has changed; I don't believe it has).

So, if the compiler is ANSI-conforming it should initialize pointers
to null pointer constants, not 0.  If it isn't ANSI-conforming, who
knows? If the static pointer is in a union, then obviously there are
problems.
-- 
Jim Patterson
Cognos Inc.

guy@gorodish.UUCP (06/05/87)

> With all due respect to Chris and K&R, what I was (poorly) trying to
> say was, that when trying to write portable code, you should never use
> a variable before it's been explicitly initialized.

That depends on what you mean by "portable".  Some people may have to
worry about porting to incorrect C implementations, others don't.  I
refuse to worry about it; if I encounter such an implementation, I
will:

	first, report the bug and determine how soon it can be fixed;

	second, if the bug can't be fixed in a timely fashion, or if
	the vendor is under the delusion that it's a feature, try to
	get some other compiler;

	third, only if all those fail, throw in a crock to get around
	the bug.

If you can't rely on static variables not explicitly initialized
being initialized to zero, what *can* you depend on?  Shall we be
careful about using the "*" operator because somebody's C compiler
might generate code to add 43 and, if the result is negative, rewind
the printer?  How common *are* implementations that don't handle
initializations properly?  How broken are those implementations in
other fashions?

>   What's that you say?  No program would ever fail to run on your
> system because someone used a "feature" defined in K&R that didn't 
> work that way on your system?  Mind telling me what you've been 
> smoking and where I can get some?  :-)  :-)  :-)

Remove the quotation marks around "feature".  Any C implementor who
wants to be taken seriously does not have the option of treating
specifications in K&R as quote "features" unquote and ignoring them.
They can *extend* things (for example, K&R doesn't mention things
like "unsigned long", and doesn't indicate that structure member
names need not be globally unique, but most C implementations these
days support "unsigned long" and non-globally-unique member names),
but not change things in ways that *break* existing code.

At some point, one hopes, the same will be true of the specifications
in the ANSI C spec, and there will be a validation suite to ensure
that the implementor *doesn't* screw up.  Art may be anything you can
get away with, but C isn't.
	Guy Harris
	{ihnp4, decvax, seismo, decwrl, ...}!sun!guy
	guy@sun.com

guy@gorodish.UUCP (06/05/87)

> I thought the C language guaranteed that there was an integral type
> large enough to hold any pointer type.  From p. 210 of the Apocrypha
> (== Appendix A of K&R :-)
> 	
> 	A pointer may be converted to any of the integral types
> 	large enough to hold it.  Whether an int or long is
> 	required is machine dependent.
> 
> Although the word "guarantee" doesn't appear here (as it does elsewhere),
> the second sentence seems to disallow the first sentence from being
> vacuously true.

More importantly, the next paragraph says:

	   An object of integral type may be explicitly converted to a
	pointer.  The mapping always carries an integer converted
	from a pointer back to the same pointer, but is otherwise
	machine dependent.

which guarantees that the pointer->integer conversion must not
discard any bits that are of any significance; i.e., any such bits
must not participate in pointer comparisons, and it must be possible
to regenerate those bits if necessary.  I don't know if these apply
to the 48-bit pointers on the Prime or not.

Fortunately, the current ANSI C draft withdraws the guarantee
extended by K&R; see the discussion in section 3.2.2.3 of the
Rationale, where it says "Since pointers and integers are now
considered incommensurate, the only integer that can be safely
converted to a pointer is the constant 0."  (This kind of bit-banging
is generally non-portable anyway; if some architecture renders it
awkward to provide a C implementation that permits this to be done in
the "straightforward" way, some non-standard way can be provided.)
	Guy Harris
	{ihnp4, decvax, seismo, decwrl, ...}!sun!guy
	guy@sun.com

blarson@castor.usc.edu.UUCP (06/05/87)

In article <414@sds.UUCP> dave@sds.UUCP (dave schmidt x194) writes:
>In article <3673@gitpyr.gatech.EDU>, allen@gitpyr.gatech.EDU (P. Allen Jensen) writes:
>> [...] The prime also has modes of operation in which
>> pointers are 48 bits even though long, int and float are all 32 bits.
>
>I thought the C language guaranteed that there was an integral type
>large enough to hold any pointer type.  From p. 210 of the Apocrypha
>(== Appendix A of K&R :-)
>	
>	A pointer may be converted to any of the integral types
>	large enough to hold it.  Whether an int or long is
>	required is machine dependent.

When a prime CONVERTS a pointer to an integer, the ring (protection) bits
are masked off, the segment and halfword offset are left shifted, and the
extend bit is moved to the least significant bit.  If the assumptions 
that the C program is running in ring 3 (user mode) and the pointer is
pointing to a multiple of 8 bits are true, no information is lost.
The only part of K&R this violates is the next sentence after those you
quoted:  "The mapping function is also machine dependant, but is intended
to be unsurprising to those who know the address structure of the machine."
Of course, this does help porting programs written by someone making the
rash assumption that all machines are byte addressed.
-- 
Bob Larson
Arpa: Blarson@Usc-Ecl.Arpa
Uucp: (several backbone sites)!sdcrdcf!usc-oberon!castor.usc.edu!blarson
			seismo!cit-vax!usc-oberon!castor.usc.edu!blarson