[comp.arch] negative addresses

wulf@uvacs.CS.VIRGINIA.EDU (Bill Wulf) (05/09/88)

Has anyone ever seen a machine with "negative addresses", that is, one
where the address space is -2**31..2**31-1 rather than 0..2*32-1??
Any thoughts on what the problems with such a scheme might be (or are)?

Why ask such a question, you ask -- well, I'm trying to remove unsigned
arithmetic from WM, and as far as I can tell, the primary (only?) use
of unsigned arithmetic is for address computations. Soooooo...

Bill Wulf

davidsen@steinmetz.ge.com (William E. Davidsen Jr) (05/10/88)

In article <2393@uvacs.CS.VIRGINIA.EDU> wulf@uvacs.CS.VIRGINIA.EDU (Bill Wulf) writes:
| Has anyone ever seen a machine with "negative addresses", that is, one
| where the address space is -2**31..2**31-1 rather than 0..2*32-1??
| Any thoughts on what the problems with such a scheme might be (or are)?

  "bits is bits," but I suspect that a lot of programs will have trouble
with non-contiguous addressing. Address wrap forces the lowest address
to "follow" the highest address, which may make io interesting.
| 
| Why ask such a question, you ask -- well, I'm trying to remove unsigned
| arithmetic from WM, and as far as I can tell, the primary (only?) use
| of unsigned arithmetic is for address computations. Soooooo...

  My gut feeling is that this is not correct, but I have no metrics at
this time to confirm or deny what you say.
| 
| Bill Wulf

-- 
	bill davidsen		(wedu@ge-crd.arpa)
  {uunet | philabs | seismo}!steinmetz!crdos1!davidsen
"Stupidity, like virtue, is its own reward" -me

oconnor@sungoddess.steinmetz (Dennis M. O'Connor) (05/10/88)

An article by davidsen@crdos1.UUCP (bill davidsen) says:
] In article <...> wulf@uvacs.CS.VIRGINIA.EDU (Bill Wulf) writes:
] | Has anyone ever seen a machine with "negative addresses", that is, one
] | where the address space is -2**31..2**31-1 rather than 0..2*32-1??
] | Any thoughts on what the problems with such a scheme might be (or are)?
] 
]   "bits is bits," but I suspect that a lot of programs will have trouble
] with non-contiguous addressing. Address wrap forces the lowest address
] to "follow" the highest address, which may make io interesting.

The lowest address ( -2**N ) does NOT follow the highest ( 2**N-1 )
in the RPM40 memory scheme. An attempt to reach the negative area
by adding two positive values generates an overflow. This is good.
An attempt to cross zero is perfectly legal. Static storage is
centered around zero, accessable using small addresses.

Existing programs may not make good use of the negative areas.
But you should be able to solve this at link time, or maybe even
at load time. At compile time, just put the heap in negative
memory and the stack in positive. Only the compiler/linker/loader
will ever know.

] | 
] | Why ask such a question, you ask -- well, I'm trying to remove unsigned
] | arithmetic from WM, and as far as I can tell, the primary (only?) use
] | of unsigned arithmetic is for address computations. Soooooo...

]   My gut feeling is that this is not correct, but I have no metrics at
] this time to confirm or deny what you say.

Unsigned arithmetic takes very little additional hardware. I've many
times been annoyed at not being able to have integer types that range
from 0..2**N-1, where N is the word size. RISC philosophy would
be to leave it in if it does not slow the machine or use a lot of
space on the chip. So you should leave it in.

] | Bill Wulf
] 	bill davidsen		(wedu@ge-crd.arpa)
--
 Dennis O'Connor   oconnor%sungod@steinmetz.UUCP  ARPA: OCONNORDM@ge-crd.arpa
    "The purpose of socialization is to teach wolves that they are sheep."

mcdonald@uxe.cso.uiuc.edu (05/10/88)

>Why ask such a question, you ask -- well, I'm trying to remove unsigned
>arithmetic from WM, and as far as I can tell, the primary (only?) use
>of unsigned arithmetic is for address computations. Soooooo...

>Bill Wulf

You must be kidding! The primary use of unsigned arithmetic is counting
numbers, of course, but there are jillions of other uses. Don't you
want to have, with 16bit words, 32768 ABOVE 32767, and the corresponding
results with other word sizes? 

rrr@naucse.UUCP (Bob Rose ) (05/10/88)

In article <2393@uvacs.CS.VIRGINIA.EDU>, wulf@uvacs.CS.VIRGINIA.EDU (Bill Wulf) writes:
> Has anyone ever seen a machine with "negative addresses", that is, one
> where the address space is -2**31..2**31-1 rather than 0..2*32-1??
> Any thoughts on what the problems with such a scheme might be (or are)?

Is there really any difference?
 
> Why ask such a question, you ask -- well, I'm trying to remove unsigned
> arithmetic from WM, and as far as I can tell, the primary (only?) use
> of unsigned arithmetic is for address computations. Soooooo...

You must be _REAL_ disperate for silicon!
Signed multiply, add and substract is the same as the unsigned counterparts
except for maybe a condition code bit. Also signed divide normally has
unsigned divide somewhere deep inside of it and its the signed divide
that normally gets left out of the instruction set (VAX of course left out
the unsigned divide but what the hey, the MC88000 has signed divide
but it just does an unsigned divide or traps on negative numbers.) Also
the primary use of unsigned numbers isn't just for address computations.
Some of us use all the bits we can get (flags, fixed-point ...)

Robert R. Rose
Northern Arizona University, Box 15600
Flagstaff, AZ 86011
                    .....!ihnp4!arizona!naucse!rrr

mahar@weitek.UUCP (Mike Mahar) (05/10/88)

In article <2393@uvacs.CS.VIRGINIA.EDU> wulf@uvacs.CS.VIRGINIA.EDU (Bill Wulf) writes:
>Has anyone ever seen a machine with "negative addresses", that is, one
>where the address space is -2**31..2**31-1 rather than 0..2*32-1??
>Any thoughts on what the problems with such a scheme might be (or are)?
>
>Why ask such a question, you ask -- well, I'm trying to remove unsigned
>arithmetic from WM, and as far as I can tell, the primary (only?) use
>of unsigned arithmetic is for address computations. Soooooo...
>
>Bill Wulf


A pretty good arguement can be made that the 68000 is a signed address
machine.  And the address displacements are signed.  There is even a short
absolute addressing mode. It uses an absolute 16-bit signed address.
Most compilers only use 32K of that address because they want memory to
start at 0.  The addressing modes of the 68000 are more orthognal if you
assume that address 0 is the middle of memory rather than the beginning.

-- 
	Mike Mahar
	UUCP: {turtlevax, cae780}!weitek!mahar

bcase@Apple.COM (Brian Case) (05/11/88)

In article <2393@uvacs.CS.VIRGINIA.EDU> wulf@uvacs.CS.VIRGINIA.EDU (Bill Wulf) writes:
>Has anyone ever seen a machine with "negative addresses", that is, one
>where the address space is -2**31..2**31-1 rather than 0..2*32-1??
>Any thoughts on what the problems with such a scheme might be (or are)?

Check out the Elxsi machine.  It has "negative" addressing.  It seems that
with negative addressing, you can get a simple address checking for free.
Put the OS Kernel in negative space, e.g.

>...as far as I can tell, the primary (only?) use
>of unsigned arithmetic is for address computations.

Yeah, same here, unless it's for some obscure purpose or is supported
directly by the source language.

henry@utzoo.uucp (Henry Spencer) (05/11/88)

> ... I'm trying to remove unsigned
> arithmetic from WM, and as far as I can tell, the primary (only?) use
> of unsigned arithmetic is for address computations. Soooooo...

I've thought for a long time that unsigned arithmetic is basically a relic
of the 16-bit days, when the difference between 15 and 16 really mattered,
and that the difference between 31 and 32 is much less significant.  I don't
see any compelling need for unsigned arithmetic on a 32-bit machine with
31-bit addresses or signed addresses... except that several of the newer
programming languages, notably C, absolutely require it.
-- 
NASA is to spaceflight as            |  Henry Spencer @ U of Toronto Zoology
the Post Office is to mail.          | {ihnp4,decvax,uunet!mnetor}!utzoo!henry

tim@amdcad.AMD.COM (Tim Olson) (05/11/88)

Note: I am also including comp.lang.c, since this also pertains to C...

In article <2393@uvacs.CS.VIRGINIA.EDU>, wulf@uvacs.CS.VIRGINIA.EDU (Bill Wulf) writes:
| Has anyone ever seen a machine with "negative addresses", that is, one
| where the address space is -2**31..2**31-1 rather than 0..2*32-1??
| Any thoughts on what the problems with such a scheme might be (or are)?

I can't think of any real problems offhand, but this representation
affects a few things:

Your program's virtual address space probably starts at -2**31,
rather than 0 (to give you the full range).  This means that C-language
null pointers, because they are defined never to point to a valid
address, will probably have to be something other than the standard
all-zero bit representation.  This is not a real problem, as C allows
this.  However, it complicates the compiler somewhat (having to detect
the assignment/comparison of a pointer and the integer constant 0 as a
special case).  Also, buggy programs that used to run with references
through uninitialized static pointers might break in horrible ways (this
is not necessarily bad! ;-)

| Why ask such a question, you ask -- well, I'm trying to remove unsigned
| arithmetic from WM, and as far as I can tell, the primary (only?) use
| of unsigned arithmetic is for address computations. Soooooo...

What about support for explicit unsigned types in HLLs?  This would only
work if you limited the range of "unsigned" values to 0..2**31-1, rather
than the full 32-bit range.  However, my copy of the ANSI C Draft Spec
(which might be out of date) says:

	"For |signed char| and each type of |int|, there is a
	corresponding unsigned type (declared with the keyword
	|unsigned|) that utilizes the same amount of storage including
	sign information.  The set of nonnegative values of a signed
	type is a subset of its corresponding unsigned type."

	-- Tim Olson
	Advanced Micro Devices
	(tim@delirun.amd.com)

schooler@oak.bbn.com (Richard Schooler) (05/11/88)

I've seen too many other uses of unsigned arithmetic to contemplate
removing unsigned arithmetic.  Some quantities are inherently
unsigned, such as distance and degrees Kelvin.  To many industrial
applications, the difference between a 15-bit and a 16-bit integer is
a critical one.  Even 31 vs. 32 bits can make a difference,
particularly in fixed-point work, where resolution counts as well as
range.  Unsigned integers are also good for bit-diddling in a language
that doesn't support it explicitly.

	-- Richard Schooler
	schooler@bbn.com

tve@alice.UUCP (05/11/88)

In article <2393@uvacs.CS.VIRGINIA.EDU>, wulf@uvacs.UUCP writes:
> Has anyone ever seen a machine with "negative addresses", that is, one
> where the address space is -2**31..2**31-1 rather than 0..2*32-1??

Is it a hardware or a software issue?
If you use physical addressing and your memory starts at zero, it is a
board hardware issue.
If you use virtual memory, it's the way the software sets up the process
and the MMU.

I think, having negative addresses is mainly a software issue, namely
having process code and static data start at -2**31 and stack start
at 2**31 (going down) (It's not exactly these numbers, but it's the general
idea).
The main hardware obstacle I see, is "short addressing". You might be
interested in the fact, that the 680x0 _sign_ extends short addresses,
which is exactly what you want for your negative address scheme (as
opposed to _zero_ extension). In fact, I seem to remember, that the
68000 manual says the address range for short adresses (16 bits)
is -2**16..2**16.

So take a 680x0 and try your kernel and compiler! If you have the
overflow/condition-code bits sorted out, your main problem will
be convincing users (and ported programs) to understand the
negative addresses!

Thorsten von Eicken		research!tve or tve@research.att.com
AT&T Bell Laboratories
Murray Hill, NJ

przemek@gondor.cs.psu.edu (Przemyslaw Klosowski) (05/11/88)

In article <2393@uvacs.CS.VIRGINIA.EDU> wulf@uvacs.CS.VIRGINIA.EDU (Bill Wulf) writes:
>Has anyone ever seen a machine with "negative addresses", that is, one
>where the address space is -2**31..2**31-1 rather than 0..2*32-1??
>Any thoughts on what the problems with such a scheme might be (or are)?
>
For one, all those nice addressing modes with index scaled by the size of the
data structure:
	EA = (base) + (index)<<(ln2 size)
won't work, unless index is restricted.



				przemek@psuvaxg.bitnet
				psuvax1!gondor!przemek

stuart@cs.rochester.edu (Stuart Friedberg) (05/11/88)

In article <389@attila.weitek.UUCP>, mahar@weitek.UUCP (Mike Mahar) writes:
> A pretty good arguement can be made that the 68000 is a signed address
> machine.  And the address displacements are signed.  There is even a short
> absolute addressing mode. It uses an absolute 16-bit signed address.

Right.  And a machine that makes use of that is the BBN Butterfly
multiprocessor.  Both the "positive" and "negative" portions of that
signed address space are used to efficiently access "Subspace Zero", where
magic memory mapped functions, implemented by a bit-slice coprocessor,
hang out.  However, the machine presents a conventional memory map (all
positive) to programmers, so Subspace Zero addresses have to be mapped
in at the very bottom and very top of the address space.

For this particular purpose, it would have been more symmetric, but far
less conventional, to regard memory space as signed.  It would have
been far more conventional, and convenient, FOR THIS PARTICULAR PURPOSE
if the 68000 provided a 16-bit absolute unsigned address, instead.

Stu Friedberg  {ames,cmcl2,rutgers}!rochester!stuart  stuart@cs.rochester.edu

jesup@pawl15.pawl.rpi.edu (Randell E. Jesup) (05/11/88)

>In article <2393@uvacs.CS.VIRGINIA.EDU> wulf@uvacs.CS.VIRGINIA.EDU (Bill Wulf) writes:
>| Has anyone ever seen a machine with "negative addresses", that is, one
>| where the address space is -2**31..2**31-1 rather than 0..2*32-1??
>| Any thoughts on what the problems with such a scheme might be (or are)?

>| Bill Wulf

	The rpm-40 has negative addressing.  (-2**N..2**N-1, where 2**(N+1) is
the process instruction or data space size.

     //	Randell Jesup			      Lunge Software Development
    //	Dedicated Amiga Programmer            13 Frear Ave, Troy, NY 12180
 \\//	beowulf!lunge!jesup@steinmetz.UUCP    (518) 272-2942
  \/    (uunet!steinmetz!beowulf!lunge!jesup) BIX: rjesup
(-: The Few, The Proud, The Architects of the RPM40 40MIPS CMOS Micro :-)

rk@lexicon.UUCP (Bob Kukura) (05/11/88)

From article <9485@apple.Apple.Com> by bcase@Apple.COM (Brian Case):
>In article <2393@uvacs.CS.VIRGINIA.EDU> wulf@uvacs.CS.VIRGINIA.EDU (Bill Wulf) writes:
>>...as far as I can tell, the primary (only?) use
>>of unsigned arithmetic is for address computations.
>
>Yeah, same here, unless it's for some obscure purpose or is supported
>directly by the source language.

Unsigned arithmetic is used in array index calculations all the time.
You only have to check one bound if the first element is at zero and
the index is unsigned.  I'm sure languages like Pascal can use the
condition codes to check for negative indices, but condition codes are
not available to the programmer in C.
-- 
-Bob Kukura		uucp: {husc6,linus,harvard,bbn}!spdcc!lexicon!rk
			phone: (617) 891-6790

nather@ut-sally.UUCP (Ed Nather) (05/12/88)

In article <9485@apple.Apple.Com>, bcase@Apple.COM (Brian Case) writes:
> In article <2393@uvacs.CS.VIRGINIA.EDU> wulf@uvacs.CS.VIRGINIA.EDU (Bill Wulf) writes:
> 
> >...as far as I can tell, the primary (only?) use
> >of unsigned arithmetic is for address computations.
> 
> Yeah, same here, unless it's for some obscure purpose or is supported
> directly by the source language.

Your CS background is showing, gentlemen.  When I gather data from stars, I
count the precious photons one at a time, and use unsigned arithmetic to
massage them, since there are no negative photons (unlike negative addresses).
I wouldn't classify this as an obscure purpose, but someone else might.

-- 
Ed Nather
Astronomy Dept, U of Texas @ Austin
{allegra,ihnp4}!{noao,ut-sally}!utastro!nather
nather@astro.AS.UTEXAS.EDU

radford@calgary.UUCP (Radford Neal) (05/12/88)

> Has anyone ever seen a machine with "negative addresses", that is, one
> where the address space is -2**31..2**31-1 rather than 0..2*32-1??
> Any thoughts on what the problems with such a scheme might be (or are)?
> 
> Why ask such a question, you ask -- well, I'm trying to remove unsigned
> arithmetic from WM, and as far as I can tell, the primary (only?) use
> of unsigned arithmetic is for address computations. Soooooo...
> 
> Bill Wulf


The 68000 has negative addresses when you're using it as a machine with
a 16-bit address space.

What do I mean by this? Well, the instructions all sign extend when
moving a 16-bit address into a 32-bit address register. E.g. 

   move.w a0@,a0

fetches a word from the address in a0, _sign extends it to 32-bits_
and replaces a0 with the result. So if you try to treat the 68000 as
a 16-bit address machine (for a speed gain), you must consider the
addresses to be signed, or go to a lot of effort to undo these sign 
extensions at times.

I've no idea if anyone writes 68000 programs like this. I was going to
once, but in the end decided I needed more than 2^16 bytes of memory.

I see only one problem with negative addresses. A C implementation will be 
much assisted by an addressing scheme in which (char*)0 has all zeros as
its bit pattern. In a machine with negative addresses, arrainging this
might be annoying. Then again, it might be no problem, if you decide on
a layout like, say:

   -large             one            +large

   program code       data ->      <- stack

This seems like a reasonable layout unless you're desparate for address
space and don't want the potential unused gap between the end of
program code and the start of data at address 1. (You want a one-byte
gap at address zero, of course, so that null is invalid.)

    Radford Neal

Paul_L_Schauble@cup.portal.com (05/12/88)

I routinely work on a machine that almost does this, the Honeywell-Bull
GCOS mainframes. Virtual addresses are constructed from three pieces

   Descriptor       34 bits of address
   Address register 34 bit signed offset
   Index register   34 bit signed offset
   Instruction      16 bit signed offset

Oops, I meant 4 pieces. This all works fine except for one idiody committed
by the hardware designers: the machine word is 36 bits. If you do an
'effective address to register' instruction that results in a negative
address does NOT result in a negative value in the register.

This machine does not consider the 34 bit final addresses to be signed. If I
were designing the machine again, I'd make all of the internal address
calculations be 36 bits, ending with a 36 bit negative value. The, just throw
away the negative half of the address space by making those addresses fault.
If you don't think losing the address space is reasonable (and on a machine
with a small 32 bit address space you might well not), then HB could just
make the virtual addresses run -X to +X and just adjust the base addresses
in the descriptors. Very very few slave processes would ever notice.

    Paul

henry@utzoo.uucp (Henry Spencer) (05/12/88)

> Your program's virtual address space probably starts at -2**31,
> rather than 0 (to give you the full range).  This means that C-language
> null pointers, because they are defined never to point to a valid
> address, will probably have to be something other than the standard
> all-zero bit representation.  This is not a real problem...

Unfortunately, it is a real problem, because there are zillions of
programs that implicitly assume that pointers are all-zeros.  It is
true that the language does not require it, but doing anything else
is an enormous pain in practice, according to the people who have
experimented with the idea.

Fortunately the problem can be bypassed, because there is absolutely no
reason why the null pointer has to point to the beginning of your address
space.  It is sufficient for the machine and the memory allocator to
conspire to ensure that no user data is ever allocated at location 0.
This would qualify as a nuisance, but hardly a disaster.

> ... it complicates the compiler somewhat (having to detect
> the assignment/comparison of a pointer and the integer constant 0 as a
> special case)...

Not by much.  Some machines already need such complications because their
pointers and integers are not the same size.

> ... uninitialized static pointers might break in horrible ways (this
> is not necessarily bad! ;-)

Are you going to fix all the programs that rely on it? ;-)  More to the
point, this is not an issue, because uninitialized static variables are
*not* initialized to all-zeros, they are initialized to the zero value
of their data type, which means the null pointer for pointers.  Now this
would be a bit of a pain for compilers on machines with odd representations
of the null pointer.
-- 
NASA is to spaceflight as            |  Henry Spencer @ U of Toronto Zoology
the Post Office is to mail.          | {ihnp4,decvax,uunet!mnetor}!utzoo!henry

ok@quintus.UUCP (Richard A. O'Keefe) (05/13/88)

In article <11571@ut-sally.UUCP>, nather@ut-sally.UUCP (Ed Nather) writes:
> In article <9485@apple.Apple.Com>, bcase@Apple.COM (Brian Case) writes:
> > In article <2393@uvacs.CS.VIRGINIA.EDU> wulf@uvacs.CS.VIRGINIA.EDU (Bill Wulf) writes:
> > >...as far as I can tell, the primary (only?) use
> > >of unsigned arithmetic is for address computations.
> > Yeah, same here, unless it's for some obscure purpose or is supported
> > directly by the source language.
> 
> Your CS background is showing, gentlemen.  When I gather data from stars, I
> count the precious photons one at a time, and use unsigned arithmetic to
> massage them, since there are no negative photons (unlike negative addresses).

Ah, backgrounds.  "unsigned" arithmetic is NOT the same as "arithmetic on
natural numbers" (N as opposed to Z).  What it means is "modulo 2^N,
_sort of_".  I don't imagine that Ed Nather likes it when his counts
silently wrap around from 65535 to 0, but that's "unsigned" arithmetic
for you.  While I agree that it is useful to distinguish counts from
other types, I'm not convinced that this is an argument for having a
machine support "unsigned" arithmetic.  If you have two counters, what
could be more natural than taking the difference?  If I do
	unsigned int counter[2];
then
	counter[1] - counter[0]
in C is an "unsigned" quantity, which ought to come as an extremely
unpleasant shock to anyone who thought "unsigned" was good for counting.

(1) ADA requires that the basic integer types are symmetric around 0
    (with perhaps an additional negative value), so on a VAX you can
    declare a subtype 0..16#7fff_ffff# but that's as far as it goes.
    Perhaps Bill Wulf could explain that the WM is meant for ADA?
(2) I am getting sick of computers which cannot do integer arithmetic
    and won't admit their mistakes.  Floating-point was bad enough,
    but when a computer will add 1 to a positive number and give me
    a negative number it's time we cleaned up our act.  I use C every
    day, but it is an antique, and enforces too many mistakes from
    the past (such as running with integer exceptions disabled).
(3) Why should the machine's wordsize show through into a programming
    language?  It's fair enough for there to be a threshold (the
    register width) below which arithmetic is fast, but if I am
    willing to declare the ranges of my variables, why shouldn't the
    compiler handle whatever size I specify?

So my vote is 
	unsigned arithmetic, no;
	support for (compiler-generated) multi-precision operations, yes.

nather@ut-sally.UUCP (Ed Nather) (05/14/88)

In article <965@cresswell.quintus.UUCP>, ok@quintus.UUCP (Richard A. O'Keefe) writes:
> 
> Ah, backgrounds.  "unsigned" arithmetic is NOT the same as "arithmetic on
> natural numbers" (N as opposed to Z).  What it means is "modulo 2^N,
> _sort of_".  

Well, er ... uh ... (blush) ...

> I don't imagine that Ed Nather likes it when his counts
> silently wrap around from 65535 to 0, but that's "unsigned" arithmetic
> for you. 

In practice my interface board watches for this overflow and yanks on a
polled interrupt line so the program can add 1 to an internal 16-bit
extension of the count.  But you make a strong point: that really
isn't the way I'd like things to behave.  I guess it's preferable to having
32768 counts represented as a negative number, but not by much.

> (2) I am getting sick of computers which cannot do integer arithmetic
>     and won't admit their mistakes.  Floating-point was bad enough,
>     but when a computer will add 1 to a positive number and give me
>     a negative number it's time we cleaned up our act.  

I agree, but I'm pretty sure floating point isn't much of an answer.  If
I try to count things by adding 1 to a floating point number, as the
count gets bigger a unit count becomes less and less significant, until
its significance is smaller than the size of the mantissa and counting 
stops completely.

Now, if we designed computers so integer word sizes were large enough to
hold the largest number we now use in floating point (ca. 2^512 or so)
then we wouldn't need a complex floating point system -- just good,
fast (wide) integer operations.  And I could count events without
constantly looking over my shoulder for problems.

-- 
Ed Nather
Astronomy Dept, U of Texas @ Austin
{allegra,ihnp4}!{noao,ut-sally}!utastro!nather
nather@astro.AS.UTEXAS.EDU

aglew@urbsdc.Urbana.Gould.COM (05/14/88)

>> >[Wulf]: 
>> >...as far as I can tell, the primary (only?) use
>> >of unsigned arithmetic is for address computations.
>> [Brian Case]:
>> Yeah, same here, unless it's for some obscure purpose or is supported
>> directly by the source language.
>[Ed Nather]:
>Your CS background is showing, gentlemen.  When I gather data from stars, I
>count the precious photons one at a time, and use unsigned arithmetic to
>massage them, since there are no negative photons (unlike negative addresses).
>I wouldn't classify this as an obscure purpose, but someone else might.

What do you care if you are counting in a signed integer, and just
use half the range?

gwyn@brl-smoke.ARPA (Doug Gwyn ) (05/14/88)

In article <1988May12.162906.16901@utzoo.uucp> henry@utzoo.uucp (Henry Spencer) writes:
>Unfortunately, it is a real problem, because there are zillions of
>programs that implicitly assume that pointers are all-zeros.

I don't think this is true.  How about an example?

>... uninitialized static variables are
>*not* initialized to all-zeros, they are initialized to the zero value
>of their data type, which means the null pointer for pointers.  Now this
>would be a bit of a pain for compilers on machines with odd representations
>of the null pointer.

Not that much of a problem, really.  The compiler knows about static
data at compile time, and if not explicitly initialized it can output
something like
	ptrname: .word 0xF0F0F0F0 ; null pointer pattern
in the data section of the code it generates.

ok@quintus.UUCP (Richard A. O'Keefe) (05/14/88)

In article <11592@ut-sally.UUCP>, nather@ut-sally.UUCP (Ed Nather) writes:
> In article <965@cresswell.quintus.UUCP>, ok@quintus.UUCP (Richard A. O'Keefe) writes:
> 
> > (2) I am getting sick of computers which cannot do integer arithmetic
> >     and won't admit their mistakes.  Floating-point was bad enough,
> >     but when a computer will add 1 to a positive number and give me
> >     a negative number it's time we cleaned up our act.  
> 
> I agree, but I'm pretty sure floating point isn't much of an answer.

I didn't suggest it was!  No way!  [Quick exercise:  supposing 32-bit
integers and 32-bit IEEE floats, find numbers X, Y, Z such that
	X.GE.Y .AND. Y.GE.Z .AND. X.LT.Z
in a conforming Fortran-77 -- declarations may be needed.]

> Now, if we designed computers so integer word sizes were large enough to
> hold the largest number we now use in floating point (ca. 2^512 or so)

My point is that "word size" is an implementation detail which is of
interest to people writing device drivers, operating systems, compilers,
&c, but that most of my programs couldn't care less.  If I declare a
512-bit integer and the machine has 32-bit registers, it's the compiler's
job to cope.  All of the machines I am familiar with except the B6700
have support for multi-precision integer arithmetic, and the B6700 could
deal with 78-bit + sign integers anyway.  What's the good of ADDC.L and
the rest if the compiler won't generate them?

I appreciate that there are applications where the "C" model is appropriate.
But why should COBOL be the only language I can do 18-digit integer
arithmetic in?  (LISP has arbitrary precision integers and rationals, but
that requires dynamic storage management, which I also like, but one dream
at a time.)

vandys@hpindda.HP.COM (Andy Valencia) (05/15/88)

	Logitech got caught by the "NIL doesn't have to be 0" syndrome.
I think they used 0xFFFF,0xFFFF.  Turns out that the 80286
architecture traps loads of invalid segment numbers into the
segment registers, but allows 0 to be loaded, and then traps the
reference instead.  So unless you're representing at least the segment
number as 0, you're not going to survive protected mode '286.
In their new compiler I believe NIL is now 0,0xFFFF.

				Andy Valencia
				vandys%hpindda.UUCP@hplabs.hp.com

nather@ut-sally.UUCP (Ed Nather) (05/16/88)

In article <28200145@urbsdc>, aglew@urbsdc.Urbana.Gould.COM writes:
> 
> >[Ed Nather]:
> When I gather data from stars, I
> >count the precious photons one at a time, and use unsigned arithmetic to
> >massage them, since there are no negative photons (unlike negative addresses).
> What do you care if you are counting in a signed integer, and just
> use half the range?

Unfortunatly I have found no simple way to get the star to cooperate with
respect to counting rates.  Sometimes 16 bits are enough, sometimes 32
aren't, depending on the the star's brightness and the rapidity with which
it varies.

But these are details.  What we are all doing, in different disciplines, is
conforming to current computer architecture rather than cutting it to fit our
particular problem.  Compilers are just a way to insert a "virtual architecture"
in between the user and the hardware so it looks different -- friendlier to 
certain applications, usually.

We pay the cost at run-time.  If we can afford it, fine.  But we continue to
ask more and more of computers as they get faster and faster, and I doubt
this is likely to change any time soon.

-- 
Ed Nather
Astronomy Dept, U of Texas @ Austin
{allegra,ihnp4}!{noao,ut-sally}!utastro!nather
nather@astro.AS.UTEXAS.EDU

henry@utzoo.uucp (Henry Spencer) (05/16/88)

> Your CS background is showing, gentlemen.  When I gather data from stars, I
> count the precious photons one at a time, and use unsigned arithmetic to
> massage them, since there are no negative photons...

Your lack of CS background is showing, Ed. :-)  Just because your numbers
are always positive doesn't mean you should use unsigned data types for
them.  As people have already pointed out, nasty surprises lurk in unsigned
arithmetic, and it is potentially less efficient to boot (although on most
machines the difference, if any, is slight).  The only compelling reason
to use unsigned data types for ordinary arithmetic purposes is if you really
need that one extra bit... and if that's the case, you're probably better
off using some sort of multi-precision arithmetic package anyway, because
sooner or later you'll need another bit.
-- 
NASA is to spaceflight as            |  Henry Spencer @ U of Toronto Zoology
the Post Office is to mail.          | {ihnp4,decvax,uunet!mnetor}!utzoo!henry

henry@utzoo.uucp (Henry Spencer) (05/16/88)

> >Unfortunately, it is a real problem, because there are zillions of
> >programs that implicitly assume that pointers are all-zeros.
> 
> I don't think this is true.  How about an example?

Any program written by a programmer who believes the 4.3BSD manuals, or
any of their ancestors, all of which claim that the arg-list terminator
for execl is 0 rather than (char *)0.  A pox on the Berkloids for not
having fixed this long ago!

I'm not intimately acquainted with the problem myself, but I do know that
at least one computer project that wanted to use a non-zero null pointer
studied the situation and decided to change the hardware instead.

>Not that much of a problem, really.  The compiler knows about static
>data at compile time, and if not explicitly initialized it can output
>something like
>	ptrname: .word 0xF0F0F0F0 ; null pointer pattern
>in the data section of the code it generates.

True, which is why I described it as "a bit of a pain" rather than as
a significant problem.  The biggest nuisance, actually, is the loss in
effectiveness of the "BSS" optimization for object-module size.
-- 
NASA is to spaceflight as            |  Henry Spencer @ U of Toronto Zoology
the Post Office is to mail.          | {ihnp4,decvax,uunet!mnetor}!utzoo!henry

billo@cmx.npac.syr.edu (Bill O) (05/16/88)

In article <11618@ut-sally.UUCP> nather@ut-sally.UUCP (Ed Nather) writes:
>In article <28200145@urbsdc>, aglew@urbsdc.Urbana.Gould.COM writes:
>> 
>> >[Ed Nather]:
>> When I gather data from stars, I
>> >count the precious photons one at a time, and use unsigned arithmetic to
>> >massage them, since there are no negative photons (unlike negative addresses).
>> What do you care if you are counting in a signed integer, and just
>> use half the range?
>
>Unfortunatly I have found no simple way to get the star to cooperate with
>respect to counting rates.  Sometimes 16 bits are enough, sometimes 32
>aren't, depending on the the star's brightness and the rapidity with which
>it varies.
>

This is a perfect example of why we need higher-level languages
like lisp.  In lisp, you don't need to know the ranges of 
integers ahead of time. If your calculations overflow the
hardware representation of an interger, lisp just converts
the representation to Bignum, and works with it instead --
you may never even be aware that the conversion has occurred.

Yes, we need languages that are close to hardware (I don't think I'd
be able to write an operating system for, say, an IBM 370, in lisp.)
But much of programming could be made easier if we used (and designed)
languages more suited to the framing of algorithms rather than to the
writing of programs which run fast on particular pieces of hardware.

In fact, using such languages has the beneficial effect of encouraging
the design of hardware better suited to higher-level language
implementation -- example: lisp machines.

(NOTE: in lisp you actually get the best of both worlds. You can
fully specify types if you choose, to get faster-running code.)

karl@haddock.ISC.COM (Karl Heuer) (05/17/88)

In article <1988May15.222335.13174@utzoo.uucp> henry@utzoo.uucp (Henry Spencer) writes:
>The biggest nuisance, actually, [with a nonzero representation for NULL] is
>the loss in effectiveness of the "BSS" optimization for object-module size.

One could implement separate segments for "integral BSS", "pointer BSS", and
"floating BSS".  Mixed-type aggregate BSS would still be the compiler's
responsibility, unless you have a really smart object format.

You'd probably also catch a few programs that (improperly) assume that
"int x; char *y;" allocates adjacent memory cells.

Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint
(In the above, "BSS" means "uninitialized static-duration data".)
--> Followup cautiously -- this article is still cross-posted <--

yuhara@ayumi.stars.flab.fujitsu.JUNET (== M. Yuhara ==) (05/17/88)

In article <2393@uvacs.CS.VIRGINIA.EDU>, wulf@uvacs.CS.VIRGINIA.EDU (Bill Wulf) writes:
> Has anyone ever seen a machine with "negative addresses", that is, one
> where the address space is -2**31..2**31-1 rather than 0..2*32-1??

Yes, yes.
TRON chip deals an address as an signed integer.
On TRONCHIP32, -2**31..-1 is called Shared-semi-Space (SS) which is shared
among processes. 0..2**31-1 is called Unshared-semi-Space (US) which is
independent among processes.
(You can think of SS as System's Space, and US as User's Space).

TRON chip architecture is designed to be extensible from 32 bit address space
through 48 (TRONCHIP48) to 64 bit address space (TRONCHIP64).

If you think SS is 2**31..2*32-1, you will have difficulty when you
extend address space. But if you think it is signed, address space can
be extended naturally.

		-2**63	+---------+
		   /	|         |
		 /	|         |
		/	|         |
	       /	|         |
-2GB+---------+ -2**31  |         |
    |  SS     |         |   SS    |
    |         |         |         |  <-- Some system parameters stay here.
  0 +=========+       0 +=========+      (such as reset vector.)
    |         |         |         |
    |  US     |         |         |
+2GB+---------+ 2**31-1 |   US    |
	       \    	|	  |
		\	|         |
		 \	|         |
		   \	|         |
		2**63-1	+---------+




-- 
Artifitial Intelligence Division
Fujitsu Laboratories LTD., Kawasaki, Japan.
Masanobu YUHARA
kddlab!yuhara%flab.flab.fujitsu.junet@uunet.UU.NET

tainter@ihlpg.ATT.COM (Tainter) (05/17/88)

In article <965@cresswell.quintus.UUCP>, ok@quintus.UUCP (Richard A. O'Keefe) writes:
> I don't imagine that Ed Nather likes it when his counts
> silently wrap around from 65535 to 0, but that's "unsigned" arithmetic
> for you. 

> (2) I am getting sick of computers which cannot do integer arithmetic
>     and won't admit their mistakes.  Floating-point was bad enough,
>     but when a computer will add 1 to a positive number and give me
>     a negative number it's time we cleaned up our act.  

It can also give you overflow if your language allows for detecting it.
Don't blaim the machine!  If you need to detect this and your language
doesn't allow it then you need a different language.

Also, There is nothing stopping the implementers from making unsigned arithmetic
(with a loss of a bit of precision) out of signed numbers.  One simply detects
the sign change and zeros out the value.  Ta da, unsigned arithmetic the way
it is defined now.

I wouldn't quibble about that extra bit either, no matter how many bits of
width you give your integers, there is someone who needs more.  Currently,
31 bits is probably just as sufficient as 32 bits.  47 will probably do just
as well as 48, 63 as 64, etc.

--j.a.tainter

alan@pdn.UUCP (Alan Lovejoy) (05/17/88)

In article <1988May15.220044.12987@utzoo.uucp> henry@utzoo.uucp (Henry Spencer) writes:
>...  As people have already pointed out, nasty surprises lurk in unsigned
>arithmetic, and it is potentially less efficient to boot (although on most
>machines the difference, if any, is slight). ...

Those are interesting assertions.  I, for one, would like to see the 
justification(s) for them.  Specifically, what are the "nasty surprises"
hiding in unsigned arithmetic that do not also exist for signed
arithmetic AS IT IS COMMONLY IMPLEMENTED IN HARDWARE?  Why should
signed arithmetic be more efficient than unsigned?

--just curious--


-- 
Alan Lovejoy; alan@pdn; 813-530-8241; Paradyne Corporation: Largo, Florida.
Disclaimer: Do not confuse my views with the official views of Paradyne
            Corporation (regardless of how confusing those views may be).
Motto: Never put off to run-time what you can do at compile-time!  

davet@oakhill.UUCP (David Trissel) (05/17/88)

In article <11592@ut-sally.UUCP> nather@ut-sally.UUCP (Ed Nather) writes:

>Now, if we designed computers so integer word sizes were large enough to
>hold the largest number we now use in floating point (ca. 2^512 or so)
>then we wouldn't need a complex floating point system -- just good,
>fast (wide) integer operations.  And I could count events without
>constantly looking over my shoulder for problems.

Having worked in the past as a systems programmer at both large commercial
as well as number-crunching installations I always found it interesting that 
COBOL was the only language I knew of which mandated support for an extended
integer data type of more than 32 bits.  (Out of curiousity I just HAD to
look at the source code for the 64 bit integer square root routines!  Yes
COBOL does support sqrt(), believe it or not.) 

That was about 10 years ago and the only thing I remember is that 
the COBOL spec required that this integer data type be able to exactly 
represent at least 19 (or was it 18?) decimal digits of precision.

It's obvious financial arithmetic requires precise results.  But I
never understood why the other languages favored by the number crunching folks
never supported a larger integer type.  Is there really no use for this?

 -- Dave Trissel  ut-sally!im4u!oakhill!davet

lisper-bjorn@CS.YALE.EDU (Bjorn Lisper) (05/17/88)

In article <493@cmx.npac.syr.edu> billo@cmx.npac.syr.edu (Bill O'Farrell)
writes:
(Ed Nather writes about the problems with counting photons from stars)
>>Unfortunatly I have found no simple way to get the star to cooperate with
>>respect to counting rates.  Sometimes 16 bits are enough, sometimes 32
>>aren't, depending on the the star's brightness and the rapidity with which
>>it varies.
>
>This is a perfect example of why we need higher-level languages
>like lisp.  In lisp, you don't need to know the ranges of 
>integers ahead of time. If your calculations overflow the
>hardware representation of an interger, lisp just converts
>the representation to Bignum, and works with it instead --
>you may never even be aware that the conversion has occurred.

A lisp implementation has other problems. Counting photons is a real-time
application and lisp is not very well equipped to deal with this. What if
the lisp interpreter decides to do a garbage collection just when a bunch of
photons are coming? Hiding representations is a nice idea but this is a
particular application where one must have close control of the
representation because of the real-time constraints.

>Yes, we need languages that are close to hardware (I don't think I'd
>be able to write an operating system for, say, an IBM 370, in lisp.)
>But much of programming could be made easier if we used (and designed)
>languages more suited to the framing of algorithms rather than to the
>writing of programs which run fast on particular pieces of hardware.
>
>In fact, using such languages has the beneficial effect of encouraging
>the design of hardware better suited to higher-level language
>implementation -- example: lisp machines.

When we are at the subject, has anyone heard anything lately about the
Japanese fifth-generation computer project related ideas to have extensive
hardware support for prolog and use it as a machine language? There was a
lot of talk about this back in -83 but since then I haven't heard too much.
This is another idea I've never believed in.

Bjorn Lisper

mangler@cit-vax.Caltech.Edu (Don Speck) (05/17/88)

One should use unsigned numbers when mixing arithmetic and logical
operators, e.g. division by shifting right, modulus by masking, etc.

There are certain optimizations along those lines that are only safe
if the compiler can be sure that the number cannot be negative
(stemming largely from the convention of rounding towards zero).

Array indices can be range-checked with a single unsigned compare.

Don Speck   speck@vlsi.caltech.edu  {amdahl,ames!elroy}!cit-vax!speck

andrew@frip.gwd.tek.com (Andrew Klossner) (05/18/88)

Doug Gwyn (gwyn@brl-smoke.ARPA) writes:

>> Unfortunately, it is a real problem, because there are zillions of
>> programs that implicitly assume that [null] pointers are all-zeros.

> I don't think this is true.  How about an example?

Sure Doug, from the system V kernel that you defend so ardently :-),
file io/tt1.c (vanilla release 3.1):

In routine ttout:

		if (tbuf->c_ptr)

appears twice.  (And in the same routine,

		if (tbuf->c_ptr == NULL)

appears twice.  Multiple hackers have clogged through here.)

In routine ttioctl:

		if (tp->t_rbuf.c_ptr) {
		if (tp->t_tbuf.c_ptr) {

The C standards I've seen so far are pretty clear in stating that the
conditional is compared against zero.  There doesn't seem to be leeway
to define pointer comparisons to be against some non-zero NULL value.

  -=- Andrew Klossner   (decvax!tektronix!tekecs!andrew)       [UUCP]
                        (andrew%tekecs.tek.com@relay.cs.net)   [ARPA]

bcase@Apple.COM (Brian Case) (05/18/88)

In article <1988May15.220044.12987@utzoo.uucp> henry@utzoo.uucp (Henry Spencer) writes:
>As people have already pointed out, nasty surprises lurk in unsigned
>arithmetic, and it is potentially less efficient to boot (although on most

Now, wait:  how does unsigned arithmetic make it less efficient to boot
the machine?  :-) :-) :-) :-)

JUST KIDDING!  IT'S A JOKE, SON.

nather@ut-sally.UUCP (Ed Nather) (05/18/88)

In article <6575@cit-vax.Caltech.Edu>, mangler@cit-vax.Caltech.Edu (Don Speck) writes:
> One should use unsigned numbers when mixing arithmetic and logical
> operators, e.g. division by shifting right, modulus by masking, etc.
> 

Indeed.  Most of the time-critical operations that must be very fast make
use of these, and other, "tricks."  When time is of the essence even an
integer multiply (rarely needed) can be too costly.  Shift-and-add
operations between two registers can multiply by 10, or 40, or such small
integers as special ceses faster than most built-in multiply operations.
One obvious problem: the multiplier is not explicit, it is implicit in
the actual operations used.  Comments help.

> There are certain optimizations along those lines that are only safe
> if the compiler can be sure that the number cannot be negative
> (stemming largely from the convention of rounding towards zero).
> 
> Array indices can be range-checked with a single unsigned compare.
> 

Has anyone considered a method for telling the compiler that numbers can
only be positive, to make use of these operations?  I thought "unsigned"
did that, but maybe I'm wrong.  If I promise not to use negative integers
anywhere, even as array indices, can you generate faster code for me?

If I had that, and C had a way to keep track of the carry bit, I
wouldn't need assembly code at all.

Well, hardly ever.

-- 
Ed Nather
Astronomy Dept, U of Texas @ Austin
{allegra,ihnp4}!{noao,ut-sally}!utastro!nather
nather@astro.AS.UTEXAS.EDU

mouse@mcgill-vision.UUCP (der Mouse) (05/18/88)

In article <10001@tekecs.TEK.COM>, andrew@frip.gwd.tek.com (Andrew Klossner) writes:
> Doug Gwyn (gwyn@brl-smoke.ARPA) writes:
[an attribution appears to have been lost, but presumably it's our
friend Andrew Klossner]
>>> Unfortunately, it is a real problem, because there are zillions of
>>> programs that implicitly assume that [null] pointers are all-zeros.
>> I don't think this is true.  How about an example?
> Sure Doug, from the system V kernel that you defend so ardently :-),
> file io/tt1.c (vanilla release 3.1):
> 		if (tbuf->c_ptr)
> 		if (tbuf->c_ptr == NULL)
> 		if (tp->t_rbuf.c_ptr) {
> 		if (tp->t_tbuf.c_ptr) {

> The C standards I've seen so far are pretty clear in stating that the
> conditional is compared against zero.  There doesn't seem to be
> leeway to define pointer comparisons to be against some non-zero NULL
> value.

But when a pointer is compared against the integer constant zero,
either explicitly (second example) or implicitly (other three
examples), the zero is cast to the appropriate pointer type, producing
whatever bit pattern is appropriate for a null pointer of that type.
(Similar things happen when assigning the integer constant zero to a
pointer.  Note that "integer constant zero" is not the same thing as
"integer expression with value zero".)  This was true in K&R and
remains true in the dpANS.

					der Mouse

			uucp: mouse@mcgill-vision.uucp
			arpa: mouse@larry.mcrcim.mcgill.edu

faustus@ic.Berkeley.EDU (Wayne A. Christopher) (05/18/88)

In article <10001@tekecs.TEK.COM>, andrew@frip.gwd.tek.com (Andrew Klossner) writes:
> >> Unfortunately, it is a real problem, because there are zillions of
> >> programs that implicitly assume that [null] pointers are all-zeros.
> 
> 		if (tbuf->c_ptr)

The trick here is that whenever a pointer is converted into an
integer (as here), the NULL pointer must be converted to the integer
0.  It doesn't matter what the bit pattern is before conversion.
Otherwise, as you say, the world would be swallowed up by huge
tidal waves and the sun would fall from the sky.  Are there any
implementations of C that use a non-0 bit pattern?  I pity the
compiler writer...

	Wayne

gwyn@brl-smoke.ARPA (Doug Gwyn ) (05/18/88)

In article <10001@tekecs.TEK.COM> andrew@frip.gwd.tek.com (Andrew Klossner) writes:
-Doug Gwyn (gwyn@brl-smoke.ARPA) writes:
->> Unfortunately, it is a real problem, because there are zillions of
->> programs that implicitly assume that [null] pointers are all-zeros.
-> I don't think this is true.  How about an example?
-		if (tbuf->c_ptr)
-		if (tbuf->c_ptr == NULL)
-		if (tp->t_rbuf.c_ptr) {
-		if (tp->t_tbuf.c_ptr) {

None of these are non-portable uses of C; none of them depend on
null pointers being represented by all-zero data.

I'm still waiting for an example...

tim@amdcad.AMD.COM (Tim Olson) (05/18/88)

In article <10001@tekecs.TEK.COM> andrew@frip.gwd.tek.com (Andrew Klossner) writes:
| Doug Gwyn (gwyn@brl-smoke.ARPA) writes:
| 
| >> Unfortunately, it is a real problem, because there are zillions of
| >> programs that implicitly assume that [null] pointers are all-zeros.
| 
| > I don't think this is true.  How about an example?
| 
| Sure Doug, from the system V kernel that you defend so ardently :-),
| file io/tt1.c (vanilla release 3.1):
| 
| In routine ttout:
| 
| 		if (tbuf->c_ptr)
| 
| appears twice.  (And in the same routine,
| 
| 		if (tbuf->c_ptr == NULL)
| 
| appears twice.  Multiple hackers have clogged through here.)
| 
| In routine ttioctl:
| 
| 		if (tp->t_rbuf.c_ptr) {
| 		if (tp->t_tbuf.c_ptr) {
| 
| The C standards I've seen so far are pretty clear in stating that the
| conditional is compared against zero.  There doesn't seem to be leeway
| to define pointer comparisons to be against some non-zero NULL value.

"NULL" wasn't being discussed, it was the internal representation of null
pointers (this seems to cause so much confusion -- how about calling the
latter a different name, like "nil"?).

As has been stated in comp.lang.c numerous times: in C, nil can be any
bit pattern, as long as it is guaranteed not to ever point to valid
data.  NULL must be 0 (or perhaps (void *)0 under ANSI).  The compiler
takes care of the appropriate conversions between NULL and nil.  The
above code is correct C.

	-- Tim Olson
	Advanced Micro Devices
	(tim@amdcad.amd.com)

sarima@gryphon.CTS.COM (Stan Friesen) (05/19/88)

In article <10001@tekecs.TEK.COM> andrew@frip.gwd.tek.com (Andrew Klossner) writes:
>Doug Gwyn (gwyn@brl-smoke.ARPA) writes:
>
>> I don't think this is true.  How about an example?
[[Of code assuming the null pointer is all zero bits]]
>
>Sure Doug, from the system V kernel that you defend so ardently :-),
>file io/tt1.c (vanilla release 3.1):
>
>		if (tbuf->c_ptr)
>
>		if (tbuf->c_ptr == NULL)
>
>		if (tp->t_rbuf.c_ptr) {
>		if (tp->t_tbuf.c_ptr) {
>
>The C standards I've seen so far are pretty clear in stating that the
>conditional is compared against zero.  There doesn't seem to be leeway
>to define pointer comparisons to be against some non-zero NULL value.

	Yes, but they ALSO require that comparing a NULL-pointer to zero
evaluate to true *whatever* the representation of the NULL-pointer. The
compiler is *also* required to convert the integer constant 0 to the
NULL-pointer on assignment. So *none* of the above examples assume anything
about the representation of the NULL-pointer, they are all strictly
conforming. There *are* cases of code that does make such assumptions.
They all have the following general form:

func1(p)
char *p;
{
	/* stuff */
}

...

func2()
{
	...
	func1(0);
}

	In this example the code assumes both the representation *and* the
size of NULL-pointer. This code is *not* portable even among existing
compilers. Nor is it even conforming, let alone strictly so. Any code of
this form only works accidentally and needs to be fixed anyway.
-- 
Sarima Cardolandion			sarima@gryphon.CTS.COM
aka Stanley Friesen			rutgers!marque!gryphon!sarima
					Sherman Oaks, CA

henry@utzoo.uucp (Henry Spencer) (05/20/88)

>		if (tp->t_tbuf.c_ptr) {
>The C standards I've seen so far are pretty clear in stating that the
>conditional is compared against zero.  There doesn't seem to be leeway
>to define pointer comparisons to be against some non-zero NULL value.

Sigh.  Not this again!  If you *read* the fine print in the standards,
you will find that this construct is 100.00000% equivalent to saying
"if (tp->t_tbuf.c_ptr != NULL) {".  In pointer contexts, which this
is, the integer constant 0 stands for "whatever bit pattern is used for
null pointers".  When p is a pointer, "if (p)", "if (p != 0)" and
"if (p != NULL)" are completely synonymous, by the definition of C.

The problem that does come up is that compilers in general cannot tell
whether a parameter in a function call is meant to be a pointer or not,
and hence cannot supply the automatic conversion.  There is also trouble
with programs that explicitly convert pointers to integers and back.
-- 
NASA is to spaceflight as            |  Henry Spencer @ U of Toronto Zoology
the Post Office is to mail.          | {ihnp4,decvax,uunet!mnetor}!utzoo!henry

phil@osiris.UUCP (Philip Kos) (05/20/88)

In article <4086@gryphon.CTS.COM>, sarima@gryphon.CTS.COM (Stan Friesen) writes:
> In article <10001@tekecs.TEK.COM> andrew@frip.gwd.tek.com (Andrew Klossner) writes:
> > There doesn't seem to be leeway
> >to define pointer comparisons to be against some non-zero NULL value.
> 
> 	Yes, but they ALSO require that comparing a NULL-pointer to zero
> evaluate to true *whatever* the representation of the NULL-pointer....

Please be careful not to confuse null pointers with NULL pointers.  Null
pointers have a formal definition within the language, but NULL pointers
don't really; NULL is just a convention and not part of the language spec.
("We write NULL instead of zero, however, to indicate more clearly that
this is a special value for a pointer", K&R first edition, pp. 97-98; "The
symbolic constant NULL is often used in place of zero, as a mnemonic to
indicate more clearly that this is a special value for a pointer", K&R
second edition, p. 102.)

I've also seen NULL defined as (char *) 0, by the way...


                                                                 Phil Kos
                                                      Information Systems
...!uunet!pyrdc!osiris!phil                    The Johns Hopkins Hospital
                                                            Baltimore, MD

radford@calgary.UUCP (Radford Neal) (05/20/88)

In article <10001@tekecs.TEK.COM>, andrew@frip.gwd.tek.com (Andrew Klossner) writes:

> >> Unfortunately, it is a real problem, because there are zillions of
> >> programs that implicitly assume that [null] pointers are all-zeros.
> 
> > I don't think this is true.  How about an example?
> 
> Sure Doug, from the system V kernel... In routine ttout:
> 
> 		if (tbuf->c_ptr)

My understanding is that this is standards-conforming and portable.
I assume that c_ptr is declared to be of pointer type. The above 
statement is equivalent to

		if (tbuf->c_ptr!=0)

which is equivalent to

		if (tbuf->c_ptr!=(char*)0)

(or (int*)0 or whatever). The expression (char*)0 is _defined_ to be
the null pointer, whatever its bit pattern may be. Note that "NULL"
has nothing to do with anything, being merely a macro found in the
<stdio.h> include file.

An example of a non-portable program is the following:

    char *p;
    int i;
    ...
    i = (int)p;
    if (i!=0)
       *p = ...; /* no guarantee that p is not null... */

Only occurences of 0 in the explicit or implicit context (...*) 0
are magically converted to null pointers.

    Radford Neal

barnett@vdsvax.steinmetz.ge.com (Bruce G. Barnett) (05/20/88)

In article <2393@uvacs.CS.VIRGINIA.EDU> wulf@uvacs.CS.VIRGINIA.EDU (Bill Wulf) writes:
|Has anyone ever seen a machine with "negative addresses"?

I believe the Sun 80386 RoadRunner has negative addresses, once you get
beyond 2 Gigabytes ( assuming you use signed integers).

	Drat! There goes my nifty sort algorithm. 

--
 :-)
-- 
	Bruce G. Barnett 	<barnett@ge-crd.ARPA> <barnett@steinmetz.UUCP>
				uunet!steinmetz!barnett

anc@camcon.uucp (Adrian Cockcroft) (05/20/88)

In article <4000@ayumi.stars.flab.fujitsu.JUNET>, yuhara@ayumi.stars.flab.fujitsu.JUNET (== M. Yuhara ==) writes:
> In article <2393@uvacs.CS.VIRGINIA.EDU>, wulf@uvacs.CS.VIRGINIA.EDU (Bill Wulf) writes:
> > Has anyone ever seen a machine with "negative addresses", that is, one
> > where the address space is -2**31..2**31-1 rather than 0..2*32-1??
> 
> Yes, yes.
> TRON chip deals an address as an signed integer.

The Inmos Transputer family also has a signed address space. The top of
the address space is at 7FFFFFFF which is where it boots from ROM, the
bottom of the address space is at 80000000 which is where the on-chip RAM
and memory mapped link engines sit. It has a special instruction "mint" for
doing a quick load of the minimum integer (80000000). Because addresses are
signed you can use normal integer comparison instructions so the instruction
set is simplified. The code generated is usually totally position
independent (the instruction set is designed that way) so absolute addresses
are only needed for talking to memory mapped hardware.

-- 
  |   Adrian Cockcroft anc@camcon.uucp  ..!seismo!mcvax!ukc!camcon!anc
-[T]- Cambridge Consultants Ltd, Science Park, Cambridge CB4 4DW,
  |   England, UK                                        (0223) 358855
      (You are in a maze of twisty little C004's, all alike...)

woerz@iaoobelix.UUCP (Dieter Woerz) (05/20/88)

In article <10001@tekecs.TEK.COM> andrew@frip.gwd.tek.com (Andrew Klossner) writes:
> ...
>In routine ttout:
>
>		if (tbuf->c_ptr)
>
>appears twice.  (And in the same routine,
>
>		if (tbuf->c_ptr == NULL)
>
>appears twice.  Multiple hackers have clogged through here.)
>
>In routine ttioctl:
>
>		if (tp->t_rbuf.c_ptr) {
>		if (tp->t_tbuf.c_ptr) {
> ...

I have to admit, that the others may not work, but I think you should
be able to tweak the compilers for that architecture to do a
comparision of such pointers with the Zero-Pointer of that
architecture, which is not necessaryly zero.

The second example is should work simply if you redefine NULL to the
value of the Zero-Pointer.

------------------------------------------------------------------------------

Dieter Woerz
Fraunhofer Institut fuer Arbeitswirtschaft und Organisation
Abt. 453
Holzgartenstrasse 17
D-7000 Stuttgart 1
W-Germany

BITNET: iaoobel.uucp!woerz@unido.bitnet
UUCP:   ...{uunet!unido, pyramid}!iaoobel!woerz

flaps@dgp.toronto.edu (Alan J Rosenthal) (05/22/88)

Henry Spencer wrote:
>>Unfortunately, it is a real problem, because there are zillions of
>>programs that implicitly assume that pointers are all-zeros.

Doug Gwyn replied:
>I don't think this is true.  How about an example?

Later, he wrote that he was still waiting for an example, so I'll provide one.

A large project on which I am currently working has many segments in
which lists of things are manipulated; to a large extent mostly for
displaying in menus, but also for other standard data processing kinds
of tasks.  There is a standardised doubly-linked list representation,
and corresponding routines.  The caller of these routines has as its
representation of the list a "head" which contains header-like
information for the list.

When I first tried to use these routines, I looked through and found
out how to do various operations.  The operation I could not find was
how to initialise a doubly-linked list after having declared the head.
It turned out that a correct initialisation was to set the three
pointers in a struct dll_head all to NULL.  Since existing code usually
happened to declare the head as either global or file static most
people forgot to bother to initialise the head.  When one was declared
as auto, people called zero((char *)&thing,sizeof(struct dll_head)),
zero() being a function which sets a region of memory to zero bits.

So there's your example.

[We have since added an initialisation function!]

ajr

--
- Any questions?
- Well, I thought I had some questions, but they turned out to be a trigraph.

henry@utzoo.uucp (Henry Spencer) (05/22/88)

> ... what are the "nasty surprises"
> hiding in unsigned arithmetic that do not also exist for signed
> arithmetic AS IT IS COMMONLY IMPLEMENTED IN HARDWARE?

Well, for example, consider that a+b>c does not imply a>c-b in unsigned
arithmetic.  (To make this more obvious, consider that b>c does not imply
c-b<0, since no unsigned number is less than zero.)  Remember too that one
unsigned number in a calculation tends to make the whole calculation be
done unsigned, by C rules, sometimes unexpectedly.

> Why should signed arithmetic be more efficient than unsigned?

Because the hardware sometimes supports it rather better.  On the machine
I'm typing this on, for example, unsigned multiplication or division is
significantly slower than the signed forms, because the hardware multiply
and divide instructions are signed-only.

henry@utzoo.uucp (Henry Spencer) (05/22/88)

If I were implementing a C compiler for a 32-bit machine, I would at least
consider the notion of making "long" 64 bits.  It would probably break a
depressing amount of code, but it would have its uses.  (NB this is also
a reason for having unsigned arithmetic in the machine, since it makes
multiprecision arithmetic easier, as I recall.)

bill@proxftl.UUCP (T. William Wells) (05/23/88)

In article <10001@tekecs.TEK.COM>, andrew@frip.gwd.tek.com (Andrew Klossner) writes:
> Doug Gwyn (gwyn@brl-smoke.ARPA) writes:
>
> >> Unfortunately, it is a real problem, because there are zillions of
> >> programs that implicitly assume that [null] pointers are all-zeros.
>
> > I don't think this is true.  How about an example?
>
> Sure Doug, from the system V kernel that you defend so ardently :-),
> file io/tt1.c (vanilla release 3.1):
>
> In routine ttout:
>
>               if (tbuf->c_ptr)
>
> appears twice.  (And in the same routine,
>
>               if (tbuf->c_ptr == NULL)

ANSI says that the two are equivalent.  Actually, ANSI says
(about `if'): "...  the first substatement is executed if the
expression compares unequal to 0.  ...".  This means that you can
think of the statement `if (x)' as `if (x != 0)'.

Note that ANSI only insists that `pointer == 0' be true if and
only if pointer is a null pointer; it makes no requirements that
the pointer actually contain any zeros.

For example, on an 8086, you could define a null pointer as one
with a zero (or any other value) offset.  An implicit or explicit
compare of the pointer to zero would then check only the offset.

An interesting point: ANSI does not define (at least not anywhere
I can find it) the result of `x == y' when x and y are both null
pointers.  Actually, a literal reading of the standard implies
that this would compare false!  Here is my reasoning.  The
standard says that "If two pointers ...  compare equal, they
point to the same object." Since a null pointer does not point to
ANY object, comparing anything to a null pointer should return
false.

I hope that this is an oversight.

alan@pdn.UUCP (Alan Lovejoy) (05/23/88)

In article <1988May22.020336.17472@utzoo.uucp> henry@utzoo.uucp (Henry Spencer) writes:
/> ... what are the "nasty surprises"
/> hiding in unsigned arithmetic that do not also exist for signed
/> arithmetic AS IT IS COMMONLY IMPLEMENTED IN HARDWARE?

>Well, for example, consider that a+b>c does not imply a>c-b in unsigned
>arithmetic.  (To make this more obvious, consider that b>c does not imply
>c-b<0, since no unsigned number is less than zero.)  Remember too that one
>unsigned number in a calculation tends to make the whole calculation be
>done unsigned, by C rules, sometimes unexpectedly.

But "a + b > c" does not imply that "a > c - b" using signed arithmetic either,
because undeflow is still possible!  For example: "2 + 1 > -32768" does 
not imply that "2 > -32768 - 1", because for 16 bit integers, "-32768 - 1"
is 32767.

/> Why should signed arithmetic be more efficient than unsigned?

>Because the hardware sometimes supports it rather better.  On the machine
>I'm typing this on, for example, unsigned multiplication or division is
>significantly slower than the signed forms, because the hardware multiply
>and divide instructions are signed-only.

This argument might be valid if we were discussing what sort of
arithmetic to use on your machine.  But the subject is what sort of
arithmetic to design into new machines.  This is comp.arch, not
comp.sys.yourmachine.

Unsigned arithmetic is just an efficient range checking mechanism.
Ranges with a lower bound of zero are quite common, and it makes sense
to support them in the hardware.
-- 
Alan Lovejoy; alan@pdn; 813-530-8241; Paradyne Corporation: Largo, Florida.
Disclaimer: Do not confuse my views with the official views of Paradyne
            Corporation (regardless of how confusing those views may be).
Motto: Never put off to run-time what you can do at compile-time!  

paul@unisoft.UUCP (n) (05/23/88)

In article <206@proxftl.UUCP> bill@proxftl.UUCP (T. William Wells) writes:
>>
>>               if (tbuf->c_ptr == NULL)
>
>ANSI says that the two are equivalent.  Actually, ANSI says
>(about `if'): "...  the first substatement is executed if the
>expression compares unequal to 0.  ...".  This means that you can
>think of the statement `if (x)' as `if (x != 0)'.
>

Correct me if I'm wrong .....

			   if (x) ...

	really means 	   if (x != 0) ....
	which really means if ((x != 0) != 0) ...
	which really means if (((x != 0) != 0) != 0) ...
	which really means if ((((x != 0) != 0) != 0) != 0) ...

				etc etc


hence the need for all these new super optimising compilers .....


		Paul

	
-- 
Paul Campbell, UniSoft Corp. 6121 Hollis, Emeryville, Ca
	E-mail:		..!{ucbvax,hoptoad}!unisoft!paul  
Nothing here represents the opinions of UniSoft or its employees (except me)
"Nuclear war doesn't prove who's Right, just who's Left" (ABC news 10/13/87)

djones@megatest.UUCP (Dave Jones) (05/24/88)

in article <959@unisoft.UUCP}, paul@unisoft.UUCP (n) says:

} 			   if (x) ...
} 
} 	really means 	   if (x != 0) ....
} 	which really means if ((x != 0) != 0) ...
} 	which really means if (((x != 0) != 0) != 0) ...
} 	which really means if ((((x != 0) != 0) != 0) != 0) ...
} 
} 				etc etc
} 
} 
} hence the need for all these new super optimising compilers .....
} 


Love it.  You made my day.

Have you ever put two packages together, and cpp says "FALSE redefined"?

That means that not one, but TWO, count 'em, TWO .h files have a
macro like

#define FALSE (0!=0)

and they aren't the same.

In the code, you're likely to see 

	if( x == FALSE )

which translates to

	if( x == (0!=0) )

which, in C,  ain't the same as if( !x ).  I call this the
"Law of the Included Muddle".

Now if they had just written the macro that way, we'd have this:

#define FALSE ((0!=0)!=FALSE)

Now we've *really* got something for your optimizing compilers to crunch on.

  if(x != ((0!=0)!=((0!=0)!=((0!=0)!= ... 

I wonder if the TRUE-believers figure that someday they'll need to redefine
TRUE to -- oh let's see -- maybe 42?



		-- Dave J.

bill@proxftl.UUCP (T. William Wells) (05/28/88)

In article <4086@gryphon.CTS.COM>, sarima@gryphon.CTS.COM (Stan Friesen) writes:
)             There *are* cases of code that does make such assumptions.
) They all have the following general form:
)
) func1(p)
) char *p;
) {
)       /* stuff */
) }
)
) ...
)
) func2()
) {
)       ...
)       func1(0);
) }
)
)       In this example the code assumes both the representation *and* the
) size of NULL-pointer. This code is *not* portable even among existing
) compilers. Nor is it even conforming, let alone strictly so. Any code of
) this form only works accidentally and needs to be fixed anyway.
) --
) Sarima Cardolandion                   sarima@gryphon.CTS.COM
) aka Stanley Friesen                   rutgers!marque!gryphon!sarima

Actually, if you are using Standard C, declare func1 with a prototype
and the problem goes away. Prototypes were invented to (among other
things) solve this kind of problem.

Perhaps this is what you intended to say?

henry@utzoo.uucp (Henry Spencer) (06/01/88)

> ... undeflow is still possible!

Underflow/overflow is possible in both signed and unsigned arithmetic,
but my experience is that people are much less likely to think about it
for unsigned arithmetic.  They're used to the idea of magnitude limits,
but not used to said limits not being roughly symmetrical around zero.

> This argument might be valid if we were discussing what sort of
> arithmetic to use on your machine.  But the subject is what sort of
> arithmetic to design into new machines...

The specific question I was answering was not that tightly phrased.
-- 
"For perfect safety... sit on a fence|  Henry Spencer @ U of Toronto Zoology
and watch the birds." --Wilbur Wright| {ihnp4,decvax,uunet!mnetor}!utzoo!henry

ericb@athertn.Atherton.COM (Eric Black) (06/02/88)

In article <8805220452.AA14606@explorer.dgp.toronto.edu> flaps@dgp.toronto.edu (Alan J Rosenthal) writes:
>
>Henry Spencer wrote:
>>>Unfortunately, it is a real problem, because there are zillions of
>>>programs that implicitly assume that pointers are all-zeros.
>
>Doug Gwyn replied:
>>I don't think this is true.  How about an example?
>
>Later, he wrote that he was still waiting for an example, so I'll provide one.
> [...description of linked list of nodes pointing to other nodes...]
>people forgot to bother to initialise the head.  When one was declared
>as auto, people called zero((char *)&thing,sizeof(struct dll_head)),
>zero() being a function which sets a region of memory to zero bits.
>
>So there's your example.

A wonderful example of non-portable code!  Essentially what you are doing
without making it explicit is punning the pointer, just as if you had
something like:
	union {
		long	ima_number;
		char	*ima_pointer;
	};
and set the bits via one union member, and looked at them via the other.

There are also "zillions of programs" that assume the order of characters
in a long, and break when moved from a VAX to a 68K, or other analogous move.

Such code should be punishable by forcing the programmer to port C programs
running under UNIX to run under PRIMOS.  (no :-)

>
>[We have since added an initialisation function!]
>
>ajr

Huzzah!  What happens now when people "forget to bother to initialise the
head"??  Buggy code is an existence proof for buggy code...  A non-portable
"safety net" for programmers of said buggy code doesn't seem to me to be
a whole lot different than device drivers that assume that all device
control and status registers look exactly like the CSR on Unibus devices;
both might be perfectly valid in the environment they assume, but are
quite wrong when taken out of that environment.

Note that such assumptions are not just machine-dependent; they can also
be compiler-dependent!

I hope there was a :-) truncated by NNTP in your article...

:-):-):-):-):-):-):-):-):-):-):-):-):-):-):-):-):-):-):-):-):-):-):-):-):-)


-- 
Eric Black	"Garbage in, Gospel out"
Atherton Technology, 1333 Bordeaux Dr., Sunnyvale, CA, 94089
   UUCP:	{sun,decwrl,hpda,pyramid}!athertn!ericb
   Domainist:	ericb@Atherton.COM

bob+@andrew.cmu.edu (Bob Sidebotham) (06/17/88)

> *Excerpts from magazines.software.z: 18-May-88 Re: negative addresses Tim*
> *Olson@amdcad.AMD.COM (1494)*

> As has been stated in comp.lang.c numerous times: in C, nil can be any
> bit pattern, as long as it is guaranteed not to ever point to valid
> data.  NULL must be 0 (or perhaps (void *)0 under ANSI).  The compiler
> takes care of the appropriate conversions between NULL and nil.  The
> above code is correct C.

>       -- Tim Olson
>       Advanced Mic

I haven't been following this discussion, but I'll add my two-bits worth
anyway:  my current practice, which is apparently not legal C, is to zero data
structures after allocating them, to guarantee the structure is in a reasonable
state.  This works well for most data types, and, I thought, for pointers.

For the moment, I will still consider this a reasonable practice, despite the
fact that it may not work on some obscure machines:  on the machines I work
with, it provides me with a safe way to initialize a data structure which is_
__immune to changes in the definition of the structure._  If I explicitly
initialize all of the fields of a structure, someone will later add a field
without remembering to add the the corresponding initializing code.

It would be preferable to have a C built-in that could be used to intitialize
all of a structure's components to "zero" values, and even more preferable if
hardware manufacturers, operating system builders, compiler writers, and, of
course, language specification writers, all recognized that 0 really is a
_very_ special value.

Bob Sidebotham
P.S. The formatting of this note for the net is beyond my control...