[comp.lang.c] Addresses of parameters

wald-david@CS.YALE.EDU (david wald) (10/26/88)

In article <35569@XAIT.Xerox.COM> g-rh@XAIT.Xerox.COM (Richard Harter) writes:
>In article <1988Oct24.172209.27031@ateng.ateng.com> chip@ateng.ateng.com (Chip Salzenberg) writes:
>>According to g-rh@XAIT.Xerox.COM (Richard Harter):
>>>     And the truth of the matter is that there is no penalty for
>>>writing portable code [...]
>
>>But there *is* a penalty in pandering to broken compilers.  If, for example,
>>a compiler breaks on:
>>
>>      foo(s) short s;
>>      {
>>          short *sp = &s;
>>          int i = *sp;
>>
>>          printf("%d\n", i);
>>      }
>
>>Then you have to invest time and effort into avoiding a language construct
>>-- taking the address of a function parameter -- that should have worked.
>>(I know that some compilers do, in fact, break this contruct.) I'm sure all
>>will agree that spent time and effort are just as much a "penalty" as
>>execution time.
>
>       This is a good example.  It contains two coding techniques that I
>do not use and, indeed, would not think of using.  The first is taking
>the address of a function parameter.  The second is initialization to a
>dynamic quantity.  Why do these things?  The latter is just asking for
>trouble.  The only reason for taking the address of a function parameter
>that I can think of is that you are calling a routine that requires a
>pointer rather than a value.  I don't know whether they are "supposed"
>to work or not and I don't care; they are dubious constructs.

I'm not sure why you consider the first of these a dubious construct.
(The second I am willing to consider a non-portable abbreviation for an
extra line of code.) I can't think of an architecture where this would
be unusually difficult to implement, and on most architectures it would
be as easy as taking the address of any automatic variable.  Is it
dubious only because there are compilers which break on it, or is there
a more basic reason?


============================================================================
David Wald                                              wald-david@yale.UUCP
						       waldave@yalevm.bitnet
============================================================================

g-rh@XAIT.Xerox.COM (Richard Harter) (10/26/88)

In article <41337@yale-celray.yale.UUCP> wald-david@CS.YALE.EDU (david wald) writes:
>In article <35569@XAIT.Xerox.COM> g-rh@XAIT.Xerox.COM (Richard Harter) writes:

>>       This is a good example.  It contains two coding techniques that I
>>do not use and, indeed, would not think of using.  The first is taking
>>the address of a function parameter.  The second is initialization to a
>>dynamic quantity....

>I'm not sure why you consider the first of these a dubious construct.
>(The second I am willing to consider a non-portable abbreviation for an
>extra line of code.) I can't think of an architecture where this would
>be unusually difficult to implement, and on most architectures it would
>be as easy as taking the address of any automatic variable.  Is it
>dubious only because there are compilers which break on it, or is there
>a more basic reason?

	There are two reasons.  One is technical, the other is a matter
of general principles.  The technical reason is that a calling sequence
parameter need not have an address.  Consider a hypothetical machine P
which passes the first n arguments through registers.  Taking the address
of such an argument would then be equivalent to taking the address of a
register.  I will grant that it is easy enough to put a kludge in the 
compiler to get around this; any parameter whose address is referred to
is copied onto the stack and that becomes the effective location.  But it
is a kludge and there is no guarantee that the compiler writers will handle
this for you (particularly in a a one pass compiler!)

	The reason that this is bad as a matter of general principles is
that the address of a calling sequence parameter is not a meaningful
thing.  Arguments in C are copies of the parameters passed.  The address
(if it exists) is the address of the copy; it is not, so to speak, an
address of a real object.  The general point is that calling sequence
parameters are a different breed of cat from other variables.  Taking the
address of a calling sequence parameter implicitly ignores one of the
respects in which they are different.

-- 

In the fields of Hell where the grass grows high
Are the graves of dreams allowed to die.
	Richard Harter, SMDS  Inc.

chris@mimsy.UUCP (Chris Torek) (10/27/88)

In article <35620@XAIT.Xerox.COM> g-rh@XAIT.Xerox.COM (Richard Harter) writes:
>...  The technical reason is that a calling sequence parameter need not
>have an address.  Consider a hypothetical machine P which passes the
>first n arguments through registers.  Taking the address of such an
>argument would then be equivalent to taking the address of a register.

(Actually, the latter is possible on some machines---e.g., Pyramids, some
PDP-11s.)

>I will grant that it is easy enough to put a kludge in the compiler
>to get around this ....  But it is a kludge and there is no guarantee
>that the compiler writers will handle this for you (particularly in a
>one pass compiler!)

I would not call it a kludge---among other things, it has been
legislated in by the dpANS for C---and I would claim that it is no
harder in a one-pass compiler than in a multi-pass compiler.  It is,
however, true that some compilers have been known to get it wrong, so
that, for instance, the following program writes NULs on certain
Sun---ahem, I mean 68000-based machines :-)  (I think the *original*
non-paging Sun 1 V7ish compiler had the bug):

	print(c) char c; { (void) write(1, &c, 1); }

>The reason that this is bad as a matter of general principles is
>that the address of a calling sequence parameter is not a meaningful
>thing.

In some languages, perhaps.  In C, no: the address of a parameter is
the address of a variable.  Parameter variables should act just like
any other local variable.  If the natural calling sequence of the
machine does not provide this, the compiler should take whatever steps
are necessary to make it appear so.  Fortunately, the dpANS agrees with
me this time. . . . :-)
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

karl@haddock.ima.isc.com (Karl Heuer) (10/27/88)

In article <35620@XAIT.Xerox.COM> g-rh@XAIT.Xerox.COM (Richard Harter) writes:
>In article <41337@yale-celray.yale.UUCP> wald-david@CS.YALE.EDU (david wald) writes:
>>In article <35569@XAIT.Xerox.COM> g-rh@XAIT.Xerox.COM (Richard Harter) writes:
>>>This is a good example.  It contains two coding techniques that I do not
>>>use and, indeed, would not think of using.  The first is taking the address
>>>of a function parameter.  The second is initialization to a dynamic
>>>quantity....
>
>>I'm not sure why you consider the first of these a dubious construct.
>>(The second I am willing to consider a non-portable abbreviation for an
>>extra line of code.)

Interesting.  I recognize that some compilers get the first one wrong (when
the argument has a type which is affected by the default argument promotions),
but I've never considered it unportable to initialize auto variables to an
arbitrary expression.

>[A] parameter need not have an address.  Consider a hypothetical machine P
>which passes the first n arguments through registers.  I will grant that it
>is easy enough to put a kludge in the compiler to get around this ... but it
>is a kludge and there is no guarantee that the compiler writers will handle
>this for you (particularly in a a one pass compiler!)

The guarantee appears in the language specification.  Similarly, I feel
justified in using expression of type "char *" even though there exist
architectures which have no natural representation of pointers to objects
smaller than an int; I assume that if they're going to call it a C compiler,
the implementors will add whatever kludges are necessary to fit the language
to their machine.

>The reason that this is bad as a matter of general principles is that the
>address of a calling sequence parameter is not a meaningful thing.  Arguments
>in C are copies of the parameters passed.  The address (if it exists) is the
>address of the copy; it is not, so to speak, an address of a real object.

I've declared it as a variable; the declaration appears as part of the
function header.  It should be just as addressible as any other variable I've
declared.

Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint

tim@crackle.amd.com (Tim Olson) (10/27/88)

In article <35620@XAIT.Xerox.COM> g-rh@XAIT.Xerox.COM (Richard Harter) writes:
| 	There are two reasons.  One is technical, the other is a matter
| of general principles.  The technical reason is that a calling sequence
| parameter need not have an address.  Consider a hypothetical machine P
| which passes the first n arguments through registers.  Taking the address
| of such an argument would then be equivalent to taking the address of a
| register.  I will grant that it is easy enough to put a kludge in the 
| compiler to get around this; any parameter whose address is referred to
| is copied onto the stack and that becomes the effective location.  But it
| is a kludge and there is no guarantee that the compiler writers will handle
| this for you (particularly in a a one pass compiler!)

You are correct: a calling sequence may stipulate that the first few
parameters are passed in registers instead of on the stack.  It is not,
however, a "kludge" to force this parameter out to memory if its address
is taken -- that is how it must work.  This is analogous to a compiler
which tries to keep local variables in registers, unless their address
is taken (i.e. ignore the "register" keyword).

| 	The reason that this is bad as a matter of general principles is
| that the address of a calling sequence parameter is not a meaningful
| thing.  Arguments in C are copies of the parameters passed.  The address
| (if it exists) is the address of the copy; it is not, so to speak, an
| address of a real object.  The general point is that calling sequence
| parameters are a different breed of cat from other variables.  Taking the
| address of a calling sequence parameter implicitly ignores one of the
| respects in which they are different.

How do you suppose varargs functions are implemented?  They must take
the address of the first parameter to "step through" the parameter list.
Are you suggesting that varargs functions are not portable and should be
avoided?


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

g-rh@XAIT.Xerox.COM (Richard Harter) (10/27/88)

In article <10124@haddock.ima.isc.com> karl@haddock.ima.isc.com (Karl Heuer) writes:
>In article <35620@XAIT.Xerox.COM> g-rh@XAIT.Xerox.COM (Richard Harter) writes:

>>>>This is a good example.  It contains two coding techniques that I do not
>>>>use and, indeed, would not think of using.  The first is taking the address
>>>>of a function parameter.  The second is initialization to a dynamic
>>>>quantity....

>>>I'm not sure why you consider the first of these a dubious construct.
>>>(The second I am willing to consider a non-portable abbreviation for an
>>>extra line of code.)

>Interesting.  I recognize that some compilers get the first one wrong (when
>the argument has a type which is affected by the default argument promotions),
>but I've never considered it unportable to initialize auto variables to an
>arbitrary expression.

	Well, I didn't say it was not portable -- I said that I wouldn't
think of using it.  I am not, therefore in a position to know whether it is
portable.  I (personally) don't think it is good form, portable or not.  It
does two things.  It makes the declarations order dependent, which is an
unnecessary source of complications.  It also mixes the notions of data
space allocation and assignment statements.  I prefer to keep the notions
distinct.  Call it a prejudice.

>>[A] parameter need not have an address.  Consider a hypothetical machine P
>>which passes the first n arguments through registers...

>The guarantee appears in the language specification.

*the* language specification.  Surely you jest.  

>Similarly, I feel
>justified in using expression of type "char *" even though there exist
>architectures which have no natural representation of pointers to objects
>smaller than an int; I assume that if they're going to call it a C compiler,
>the implementors will add whatever kludges are necessary to fit the language
>to their machine.

	The cases are not similar.  Expressions of type "char *" are
fundamental to the language.  Taking the address of a calling sequence
parameter is an oddity, much as 5["foobar"] is an oddity.  One avoids
using oddities because they are intellectual clutter; the fact that you
avoid thereby one of the major ways in which compilers break is simply a
bonus.  Are you sure, by the way, that such a guarantee is in the major
language specifications?  Taking an address is not invariably guaranteed.
Indeed, taking the address of a register variable is specifically forbidden.
You may not take the address of a variable if it does not have one.  Is
this explictly stated K&R that parameters have addresses?  In H&S?  In
ANSI?

>>The reason that this is bad as a matter of general principles is that the
>>address of a calling sequence parameter is not a meaningful thing.  Arguments
>>in C are copies of the parameters passed.  The address (if it exists) is the
>>address of the copy; it is not, so to speak, an address of a real object.

>I've declared it as a variable; the declaration appears as part of the
>function header.  It should be just as addressible as any other variable I've
>declared.

	Granted.  As in:

	foo(thing)
		int *thing;
	{register int i; thing = &i;}

Parameters are a different kind of thing from automatic and static variables.
There are slightly different rules for them.  Be that as it may, you didn't
address (you should excuse the expression) the point, which is that taking
the address of a parameter is not a useful kind of thing to do.

>
>Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint


-- 

In the fields of Hell where the grass grows high
Are the graves of dreams allowed to die.
	Richard Harter, SMDS  Inc.

henry@utzoo.uucp (Henry Spencer) (10/27/88)

In article <35620@XAIT.Xerox.COM> g-rh@XAIT.Xerox.COM (Richard Harter) writes:
>... The technical reason is that a calling sequence
>parameter need not have an address...
>... Arguments in C are copies of the parameters passed.  The address
>(if it exists) is the address of the copy; it is not, so to speak, an
>address of a real object.  The general point is that calling sequence
>parameters are a different breed of cat from other variables...

Sorry, not so.  C parameters are defined, and have been defined for a
long time, to be local variables that are initialized to the values
supplied by the caller.  They are specifically *not* a different breed
of cat from other local variables.  They are real objects; if the &
operator is used on one (legally, i.e. in the absence of "register"),
the parameter must have an address.  This admittedly makes extra work
for implementations that normally pass parameters in registers, but
that's part of the job.  A compiler that botches this is broken.
-- 
The dream *IS* alive...         |    Henry Spencer at U of Toronto Zoology
but not at NASA.                |uunet!attcan!utzoo!henry henry@zoo.toronto.edu

barmar@think.COM (Barry Margolin) (10/28/88)

In article <35664@XAIT.Xerox.COM> g-rh@XAIT.Xerox.COM (Richard Harter) writes:
>taking the address of a parameter is not a useful kind of thing to do.

Why not?  You are assuming that taking the address of a variable is
only used when you plan to use it as an output parameter for a
function.  There are, however, functions that take pointers to input
data.  A good example is write(), which takes a pointer to the data to
be written.  Suppose you write a function that takes a structure as a
parameter, and it wants to write that structure to a file, using
write().  It will either take the address of the structure parameter,
or it will have to make an automatic copy of the structure and take
the address of that.  I think taking the address of the parameter is
preferable to making ANOTHER copy of the structure (the first copy has
to be made during the calling sequence of the function).

Barry Margolin
Thinking Machines Corp.

barmar@think.com
{uunet,harvard}!think!barmar

guy@auspex.UUCP (Guy Harris) (10/28/88)

>How do you suppose varargs functions are implemented?  They must take
>the address of the first parameter to "step through" the parameter list.

Umm, how "varargs" functions are implemented is a function of how
they're implemented; they are *generally* implemented in the fashion you
describe, but there is no *requirement* that they be so implemented. 
<varargs.h> (or <stdarg.h> as in the draft ANSI C standard) can be
implemented however the vendor chooses, as long as they Do The Right
Thing.

karl@haddock.ima.isc.com (Karl Heuer) (10/28/88)

In article <35664@XAIT.Xerox.COM> g-rh@XAIT.Xerox.COM (Richard Harter) writes:
>In article <10124@haddock.ima.isc.com> karl@haddock.ima.isc.com (Karl Heuer) writes:
>>I've never considered it unportable to initialize auto variables to an
>>arbitrary expression.
>
>Well, I didn't say it was not portable -- I said that I wouldn't think of
>using it.

I was responding to the previous poster, who considered it a "non-portable
abbreviation for an extra line of code".  I agree, btw, that there are things
to be avoided in this area as a matter of style (I won't list them, lest I
start a new flame war), but I don't take it to the extreme that you do.

>>Similarly, I feel justified in using expression of type "char *" even though
>>there exist [word-based] architectures ...
>
>The cases are not similar.  Expressions of type "char *" are fundamental to
>the language.  Taking the address of a calling sequence parameter is an
>oddity ...

I think it's merely a difference in degree.  If someone tried to market an
alleged C compiler that couldn't handle "char *", they'd be laughed out of
existence.  If they get sloppy on parameter addressing, they can probably
shrug it off as a "minor bug" for a while.

>Are you sure, by the way, that such a guarantee is in the major language
>specifications?  Taking an address is not invariably guaranteed.

Yes, I'm sure.  It's implicit in K&R (which is not, and was not intended to
be, a precise language specification).  According to the dpANS (the formal
spec), the only lvalues that cannot be &'d are registers and bitfields.
(There also exist lvalues that are not modifiable, namely arrays and consts;
this is an orthogonal concept.)

>>I've declared it as a variable; the declaration appears as part of the
>>function header.  It should be just as addressible as any other variable
>>I've declared.
>
>{register int i; thing = &i;}

My statement stands.  Non-parameter variables are addressible if and only if
they are not declared register; the same holds for parameters.  This makes it
"just as addressible".

>[The point is] that taking the address of a parameter is not a useful kind of
>thing to do.

I'll grant that it's not all that common, but I think it can be as useful as
taking the address of an auto variable, and for the same reasons.  In effect,
a parameter *is* an auto variable which is initialized to the value of the
actual argument.

Your reasoning raises a couple of other questions.  Do you ever change the
value of a parameter variable, or do you treat it as a constant?  Do you ever
declare a formal parameter with the "register" keyword?

Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint

wald-david@CS.YALE.EDU (david wald) (10/30/88)

In article <10164@haddock.ima.isc.com> karl@haddock.ima.isc.com (Karl Heuer) writes:
>In article <35664@XAIT.Xerox.COM> g-rh@XAIT.Xerox.COM (Richard Harter) writes:
>>In article <10124@haddock.ima.isc.com> karl@haddock.ima.isc.com (Karl Heuer) writes:
>>>I've never considered it unportable to initialize auto variables to an
>>>arbitrary expression.
>>
>>Well, I didn't say it was not portable -- I said that I wouldn't think of
>>using it.
>
>I was responding to the previous poster, who considered it a "non-portable
>abbreviation for an extra line of code".

I'm afraid I was just adding confusion here.  By non-portable I meant
that I wouldn't be surprised to find compilers that couldn't deal with
it.

>Do you ever change the value of a parameter variable, or do you treat it
>as a constant?

If "do you" is a question of style, my answer is "never." I can't think
of any real excuse for doing it, and, as a matter of style, I like to
know that the parameters passed into a function I'm writing are always
available, and right where I think they are.



============================================================================
David Wald                                              wald-david@yale.UUCP
						       waldave@yalevm.bitnet
============================================================================

pausv@teorix.liu.se (Paul Svensson) (10/30/88)

In article <29781@think.UUCP> barmar@kulla.think.com.UUCP (Barry Margolin) writes:
>In article <35664@XAIT.Xerox.COM> g-rh@XAIT.Xerox.COM (Richard Harter) writes:
>>taking the address of a parameter is not a useful kind of thing to do.
>
	[edited]
>the address of that.  I think taking the address of the parameter is
>preferable to making ANOTHER copy of the structure (the first copy has
>to be made during the calling sequence of the function).
>

The OBVIOUS solution is of course to pass the structure by address
in the first place, if you're so afraid of copying it.

Yes, I agree with Barry that taking tha address of a parameter is not
very useful, but that is NOT a good reason for not allowing it.
There are other good reasons, such as making it easier to pass arguments
in registers, for example.  On some machines, like the pdp-10, taking
the address of a register (or a bitfield, but i digress) is easy, on
others its just plain IMPOSSIBLE.  To allow "&" to work on parameters
is essentially the same as to allow it to work on register variables,
it requires the same kind if "fixes" to the compiler. (Unless parameters
are always passed on the stack, an arcane and resource-wasting policy.)

		/Paul

g-rh@XAIT.Xerox.COM (Richard Harter) (10/31/88)

In article <10164@haddock.ima.isc.com> karl@haddock.ima.isc.com (Karl Heuer) writes:
>In article <35664@XAIT.Xerox.COM> g-rh@XAIT.Xerox.COM (Richard Harter) writes:

>Your reasoning raises a couple of other questions.  Do you ever change the
>value of a parameter variable, or do you treat it as a constant?

	Sometimes I do change the value.  I never [:-)] write code without
basing it in a paradigm or model of construction.  In the most common model
parameters represent fixed inputs, outputs to be returned, and values to be
updated.  The latter two categories are conveniently handled with pointers,
again unchanged.  [I never pass or return structures.]  However there is a
situation in which it is natural to alter a parameter value, that being when
the parameter is the principle value in the main control loop.  Thus

process_node (s) node *s; {
  while (s) {
    ... code operating on node
    s = s->link;
    }
  }

>Do you ever declare a formal parameter with the "register" keyword?

	Surely you jest!
-- 

In the fields of Hell where the grass grows high
Are the graves of dreams allowed to die.
	Richard Harter, SMDS  Inc.

jpdres10@usl-pc.usl.edu (Green Eric Lee) (11/01/88)

In article <10164@haddock.ima.isc.com> karl@haddock.ima.isc.com (Karl Heuer) writes:
>In article <35664@XAIT.Xerox.COM> g-rh@XAIT.Xerox.COM (Richard Harter) writes:
>>Are you sure, by the way, that such a guarantee is in the major language
>>specifications?  Taking an address is not invariably guaranteed.
>
>Yes, I'm sure.  It's implicit in K&R (which is not, and was not intended to
>be, a precise language specification).  According to the dpANS (the formal
>spec), the only lvalues that cannot be &'d are registers and bitfields.
>(There also exist lvalues that are not modifiable, namely arrays and consts;
>this is an orthogonal concept.)

Note that many machines with large register sets or register windows
machines have optimizing compilers that keep ALL local automatic
simple variables in registers, not only variables declared
specifically as "register". This wrecks havoc with Unix. That's why
the Pyramid 90x has the bogosity of a memory-mapped register window
stack (so that you CAN take the address of a variable and have it mean
something). That won't help the AMD29000 or the SPARC much, though. I
suspect that what will happen then is that when the optimizer is
deciding what register to allocate for what, it'll notice that you're
taking the address of that particular variable -- thus forcing it into
RAM, which is a performance hit if you use that variable often (e.g. a
"char *" auto-incremented in a loop will be 6 times slower in RAM on
the AMD than it would be in a register).

--
Eric Green   {mit-eddie,osu-cis,...}!killer!elg, killer!usl!elg

ok@quintus.uucp (Richard A. O'Keefe) (11/02/88)

In article <1013@teorix.liu.se> pausv@teorix.liu.se (Paul Svensson) writes:
>Yes, I agree with Barry that taking tha address of a parameter is not
>very useful, but that is NOT a good reason for not allowing it.
>There are other good reasons, such as making it easier to pass arguments
>in registers, for example. ... To allow "&" to work on parameters
>is essentially the same as to allow it to work on register variables,

All the compiler has to do if it sees & applied to an argument is to
spill that argument to memory and use the in-memory version.  Most of
the RISC machines I've looked at adopt a convention where non-scalar
and "excess" arguments are passed in a block on the stack, and gaps are
left for the arguments which are assigned to registers, so each argument-
in-a-register has a slot reserved for it in memory anyway.

tim@crackle.amd.com (Tim Olson) (11/04/88)

In article <84@usl-pc.usl.edu> elg@killer.UUCP (Eric Lee Green) writes:
| Note that many machines with large register sets or register windows
| machines have optimizing compilers that keep ALL local automatic
| simple variables in registers, not only variables declared
| specifically as "register". This wrecks havoc with Unix.

How so?

| That's why
| the Pyramid 90x has the bogosity of a memory-mapped register window
| stack (so that you CAN take the address of a variable and have it mean
| something). That won't help the AMD29000 or the SPARC much, though. I
| suspect that what will happen then is that when the optimizer is
| deciding what register to allocate for what, it'll notice that you're
| taking the address of that particular variable -- thus forcing it into
| RAM,

That is precisely what happens.

| which is a performance hit if you use that variable often (e.g. a
| "char *" auto-incremented in a loop will be 6 times slower in RAM on
| the AMD than it would be in a register).

Not so.  Just because a variable has been aliased to memory does not
mean that a local copy cannot also be kept in the register file and used
from there.  The compiler just has to ensure that the memory copy is
updated correctly.  To use your example:

	inner loop where p			inner loop where p
	is in a register			is aliased to memory

;               sum += *p++;		;               sum += *p++;     
        load    0,17,gr121,lr6		        load    0,17,gr121,lr6    
        add     gr119,gr119,1			add     lr6,lr6,1        
        exbyte  gr121,gr121,0		        exbyte  gr121,gr121,0    
        add     gr120,gr121,gr120	        add     gr120,gr121,gr120
        cplt    gr121,gr119,10		        add     gr119,gr119,1    
        jmpt    gr121,L00012		        cplt    gr121,gr119,10   
        add     lr6,lr6,1		        jmpt    gr121,L00012      
					        store   0,0,lr6,lr2      

It is only one instruction longer when the variable is aliased to
memory.

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

chip@ateng.ateng.com (Chip Salzenberg) (11/13/88)

According to g-rh@XAIT.Xerox.COM (Richard Harter):
>	Well, I didn't say it was not portable -- I said that I wouldn't
>think of using it.  I am not, therefore in a position to know whether it is
>portable.

Finally, something we can all agree on.
-- 
Chip Salzenberg             <chip@ateng.com> or <uunet!ateng!chip>
A T Engineering             Me?  Speak for my company?  Surely you jest!
	   Beware of programmers carrying screwdrivers.