[net.lang.c] lint, pointers, 0

breuel@harvard.ARPA (Thomas M. Breuel) (02/06/85)

[in reply to Doug Gwyn's remarks...]

[ignoring return values]

Many functions in 'C' return helpful values, which can, however, safely
be ignored most of the time. Cluttering your code with '(void)' may
look impressive and improve your productivity (in lines/hour), but is not
going to help the portability or readability of your program. In
particular, putting in the cast to void can become as much of a reflex
leaving it out.

[lint]

Sure, lint is very useful for porting and debugging programs. You run
it on your code, look at its complaints, and fix them if you think that
they are justified.  I find it extremely silly, though, to put in all
these little 'comments with side effects' just to make it shut up. They
look ugly and are worthless as documentation.  If you get so many
unjustified complaints from lint that you actually need
'/*FOOBAR*/' and friends, then there is probably something wrong
with your code...

[sizeof(int)!=sizeof(char *)]

Sure, K&R did not explicitely demand anything else. Many programmers,
due to the lack of a standard document, and due to the universal
acceptance of sizeof(int)==sizeof(char *) in the early days of 'C',
have written many of programs that rely on it, though. It is moot to
argue that these programmers were wrong: their programs still exist,
work, and are used (ever cc'ed 'sed'?).

Apart from habit, there are also the problems you will run into when
implementing the generic null pointer in a 'C' in which sizeof(int)!=
sizeof(char *).

Finally, there is no good reason for not having
sizeof(int)==sizeof(char *).  'int' is not guaranteed to be the fastest
integer type around (speedof(int)<=speedof(short) on practically all
machines...). And if you are worried about getting an efficient integer
type portably, why don't you just use 'typedef short EfficientInt;' :-?

K&R (quoting from my mind) calls 'int' the 'natural' choice for an
integer data type on the target machine. In my opinion, the 'natural
choice' is the size of a pointer (the largest pointer that is).

[null pointer]

I don't care whether the null pointer spells out Mona Lisa in EBCDIC,
as long as I can compare it to '0', assign it as '0', and (sorry, I
like it) pass it as '0' where a pointer should go -- without casting,
the way K&R intended (and partially documented it). While we are on the
subject, what about the same treatment for '-1', the (de facto) standard
error return value?

Altogether:

A 'C' compiler with sizeof(int)!=sizeof(char *) has severe problems in
the real world (I speak from experience, I am working with one), and is
not going to do you much good.

						Thomas.

gwyn@brl-tgr.ARPA (Doug Gwyn <gwyn>) (02/06/85)

(void) is an operation.  Performing it when it is called for
should be no problem; apart from printf()/putc()/strcpy(),
one usually SHOULD test the return value of most functions.
I find very few occasions other than those just mentioned
when it is appropriate to discard the result of a function.
Explicit use of (void) precisely documents one's intention.

The /*<whatever>*/ lint pragmas are seldom needed in clean
code.  I find I need at most one every several hundred lines.

The reasons for not always having sizeof(char *) == sizeof(int)
have been explained several times.  The simplest examples I can
give are the Honeywell (CCC) x16 and the CDC 17xx which had 16-bit
words and were word-addressable.  To address all 128Kb (actually
less, due to chained indirect addressing) one would have to use
two words for a (char *), but only one for an (int *) or (int).
It would be absolute folly to use double words for the latter.

It is true that much code written in the days when there was only
one C compiler (Ritchie's, for the PDP-11) did not pay attention
to distinguishing among different data types, since the programmer
"knew" what the generated code would be.  Those days should have
ended with 7th Edition UNIX, when many of the portability features
were added to C (because they were needed, not because of any
academic concerns for coding purity).  Unfortunately Berkeley did
not help much with their 4BSD VAXisms (sizeof(int) == sizeof(long),
for example), although recently they have been better about this.

Just because one is using a machine with particular characteristics
is no reason to disparage those who wish their code to run, and run
well, across a wide variety of machines.  Go ahead and hack away in
your private little universe, but be aware why people at other
sites may not want to go through the trouble it would take to try
to use your code on their systems.

guy@rlgvax.UUCP (Guy Harris) (02/06/85)

> Many functions in 'C' return helpful values, which can, however, safely
> be ignored most of the time. Cluttering your code with '(void)' may
> look impressive and improve your productivity (in lines/hour), but is not
> going to help the portability or readability of your program. In
> particular, putting in the cast to void can become as much of a reflex
> leaving it out.

Sorry, Doug is right; explicitly flagging discarded return values is
often useful - it warns the reader that the code may not be checking
for error returns (if I had a nickel for each time I've been burned by
a program not checking for error returns I could single-handedly eliminate
the deficit).

> [sizeof(int)!=sizeof(char *)]
> 
> Sure, K&R did not explicitely demand anything else. Many programmers,
> due to the lack of a standard document, and due to the universal
> acceptance of sizeof(int)==sizeof(char *) in the early days of 'C',
> have written many of programs that rely on it, though. It is moot to
> argue that these programmers were wrong: their programs still exist,
> work, and are used (ever cc'ed 'sed'?).

So?  Before "termcap" existed, people wrote programs that controlled display
terminals by directly using control strings which were compiled into
the program.  These programs still exist, work, and are used, but they are
useless at a site which doesn't have the terminal they were written for.
*Modern* programs should be written to use things like "termcap", and
old programs may have to be rewritten.  That's life.  We had to bash a
number of System III programs to make them more type-correct to run on
our 16-bit-"int"/32-bit-pointer machine (and to keep them from trying
to dereference null pointers).

> Apart from habit, there are also the problems you will run into when
> implementing the generic null pointer

"Implementing the generic null pointer" is like "trisecting an angle
with compass and straightedge".  There is no generic null pointer in C
(as has been pointed out in this newsgroup far too many times already).
As such, the problems of "implementing the generic null pointer" are
irrelevant.
> 
> Finally, there is no good reason for not having
> sizeof(int)==sizeof(char *).  'int' is not guaranteed to be the fastest
> integer type around

To quote from K&R (p. 183):

	``Plain'' integers have the natural size suggested by the
	host machine architecture...

The Motorola 68000 speaks with forked tongue here.  16 bits is suggested
by the 16-bit data paths used for non-address arithmetic (2 extra clocks
for a 32-bit "add", f'rinstance), by the lack of 32-bit multiply or
divide instructions, and by the 16-bit external bus.  32 bits is suggested
by the large address space.  There is, thus, a good reason for having
sizeof(int) == 2 and sizeof(char *) == 4 - speed of execution.  There is
also a good reason for having them both == 4 - it would be nice to have
an "int" hold the size of an object larger than 65535 bytes.  There's
a tradeoff here; depending on your application, either one could be the
correct choice.

> And if you are worried about getting an efficient integer type portably,
> why don't you just use 'typedef short EfficientInt;' :-?

That's the best solution, but it doesn't help completely; arguments to
procedures have to be widened to "int".

> [null pointer]
> 
> I don't care whether the null pointer spells out Mona Lisa in EBCDIC,
> as long as I can compare it to '0', assign it as '0', and (sorry, I
> like it) pass it as '0' where a pointer should go -- without casting,
> the way K&R intended

Oh?  Have you asked K or R about this?  Do you think that the following
code:

	double foo(x)
	double x;
	{
		double sqrt();

		return(sqrt(x));
	}

	main()
	{
		printf("%f == 2\n", sqrt(4));
	}

should work?  It doesn't.  You have to cast the "4" to "(double)4", because
the current C language has no way of telling the compiler that arguments
passed to "foo" should be cast to "double".  The same holds true for
pointers.  The ANSI C language standard permits you to declare the
types of the arguments of a function, which makes 99% of these problems
go away.

> While we are on the subject, what about the same treatment for '-1',
> the (de facto) standard error return value?

What?  What treatment?  Return values don't have this problem because
you can declare the return value of a function.  (BTW, it is NOT the
standard error return value; "fopen", for instance, returns a null FILE
pointer if it fails.)

> A 'C' compiler with sizeof(int)!=sizeof(char *) has severe problems in
> the real world (I speak from experience, I am working with one), and is
> not going to do you much good.

I am also speaking with experience, I am working with such a compiler, it
has done us quite a bit of good (it permits us to write our system and
applications code in C, and we *do* make money selling that code) - a
32-bit "int" compiler might do better, but further the deponent sayeth
not - and the main problems we have are not problems with the compiler,
but problems with people who don't take sufficient care when writing
code for it.

	Guy Harris
	{seismo,ihnp4,allegra}!rlgvax!guy

guy@rlgvax.UUCP (Guy Harris) (02/06/85)

> (void) is an operation.  Performing it when it is called for
> should be no problem; apart from printf()/putc()/strcpy(),
> one usually SHOULD test the return value of most functions.

Even in the first two cases, it can be useful to test the return
value, so that you can tell when a write fails (and let the poor user
know that they've run out of space, or tried writing to a bad block,
before the "fclose"; the reason 4.xBSD blasts the "out of space" messages
to the user's terminal is probably that so few UNIX programs bother to
check for the success of "write"s).  "putc" is a nuisance, because
you don't want to check on every "putc", just on those that actually
write to the disk.  I've cooked up "ifgetc" and "ifputc" macros that
make this possible (the syntax is a bit ugly, but that's life).
Unfortunately, they're based on the "getc" and "putc" macros from "stdio.h",
and as such are protected by the terms of the UNIX license (and won't work
on different implementations of the Standard I/O library anyway),
but the trick is to do something like

	if (there's room(for putc)/data(for getc) in the buffer)
		put it there/get it from there;
	else if (flush(for putc)/fill(for getc)) fails

and write code like

	for (;;) {
		c = generate_character();
		ifputc(c, stdout) {
			perror("writing to stdout");
			done(1);
		}
	}

Also, another point on type-correctness: even on a Motorola 68000
implementation with 32-bit "int"s, you can lose if you don't declare
functions which return pointers.  See the article in the Dallas USENIX
proceedings by the people from Motorola on the System V microport.
The AT&T compiler (and, I'm told, the Sun compiler), put the return
value of pointer-valued functions in A0 - NOT in D0.  As such, if you don't
declare "malloc" as returning "char *", its caller will expect the return
value to be in D0 and will get whatever junk was there last.

This is NOT (1000 times NOT) a valid reason to putting the return value in D0.
It IS a valid reason for running your code through "lint".  C implementations
should not be governed by the problems of existing nonportable code; "lint"
(as many of us are getting tired of saying) can be used to catch those quite
nicely.

Lots of us have no trouble using "lint".  Lots of us have no trouble
declaring functions and putting casts in front of NULL, or in front of
functions whose return value we're ignoring.  It's a pain to use your turn
signal before turning - as evidenced by the number of people who don't do
it - but it's worth doing.  Trust me, it's worth doing.  The same applies
for trying to write type-correct code.

	Guy Harris
	{seismo,ihnp4,allegra}!rlgvax!guy

ron@brl-tgr.ARPA (Ron Natalie <ron>) (02/07/85)

> Finally, there is no good reason for not having
> sizeof(int)==sizeof(char *).  'int' is not guaranteed to be the fastest
> integer type around (speedof(int)<=speedof(short) on practically all
> machines...). And if you are worried about getting an efficient integer
> type portably, why don't you just use 'typedef short EfficientInt;' :-?
> K&R (quoting from my mind) calls 'int' the 'natural' choice for an
> integer data type on the target machine. In my opinion, the 'natural
> choice' is the size of a pointer (the largest pointer that is).

Yes there is!  There is no good reason for you to be too lazy to allow it.
C is a systems programming language.  I balk at having it bastardized into
an unusable higher level language.  You can not make an assumption about
the sizes.  The implementation of the compiler types should be the best
for the operation of that system.  If you care not to write code that is
portable to those machines, thats your affair, but I can't justifying adding
an artificial restriction on the language just to make you happy.
Quoting K&R from the book: "Plain" integers have the natural size suggested
by the host machine architecture.  This means WORD size on most machines,
since that is arithmatically the basic element.  Newer machines with
larger word sizes may have smaller pointer sizes, older machines with
smaller word sizes required larger pointers.

STOP RUINING C FOR SYSTEMS PROGRAMMING.

 
> [null pointer]
> 
> I don't care whether the null pointer spells out Mona Lisa in EBCDIC,
> as long as I can compare it to '0', assign it as '0', and (sorry, I
> like it) pass it as '0' where a pointer should go -- without casting,

The new C standard allows you to do this.  But what do you want the 
compiler to do now, be clairvoyant?  How is it supposed to tell that
0 is indeed a pointer, rather than the plain integer constant when
passed to a function, so that it can change the size (or in your case)
map it to MONALISA in EBCDIC.

> The way K&R intended (and partially documented it).	

It isn't clear that they ever intended it to work this way.

> While we are on the
> subject, what about the same treatment for '-1', the (de facto) standard
> error return value?
> 
Why not say that all integers are mappable to pointers, hey lets do away
with types at all!

jon@cit-vax (Jonathan P. Leech) (02/07/85)

>
>	...  The ANSI C language standard permits you to declare the
> types of the arguments of a function, which makes 99% of these problems
> go away.
>	 Guy Harris
>	 {seismo,ihnp4,allegra}!rlgvax!guy

	Does the standard require compilers to generate warnings  when
they have to generate a cast of function arguments? The potential  for
truly sloppy coding seems enormous with this change.

	Speaking of the standard, does anyone know  when  it  will  be
available for public comment?

	-- Jon Leech
	   jon@cit-vax.arpa

km@cadre.UUCP (02/08/85)

In article <366@harvard.ARPA> breuel@harvard.UUCP writes:
>
>Finally, there is no good reason for not having
>sizeof(int)==sizeof(char *).  'int' is not guaranteed to be the fastest
>integer type around (speedof(int)<=speedof(short) on practically all
>machines...). And if you are worried about getting an efficient integer
>type portably, why don't you just use 'typedef short EfficientInt;' :-?
>
>K&R (quoting from my mind) calls 'int' the 'natural' choice for an
>integer data type on the target machine. In my opinion, the 'natural
>choice' is the size of a pointer (the largest pointer that is).
>

Indeed? And what about the 8086, or worse yet, 8088? A full pointer
is a 20 bit address which must be specified by a 32 bit value  (a
16 bit offset and 16 bit segment which overlap for all but 4 bits!).
Add to that the 8088, which has 16 bit registers but does transfers
8 bits at a time. What is the "natural" choice for an int on these
machines, and why should it have anything at all to do with their
pointer architecture?


Ken Mitchum
cadre.ARPA

shannon@sun.uucp (Bill Shannon) (02/08/85)

> Also, another point on type-correctness: even on a Motorola 68000
> implementation with 32-bit "int"s, you can lose if you don't declare
> functions which return pointers.  See the article in the Dallas USENIX
> proceedings by the people from Motorola on the System V microport.
> The AT&T compiler (and, I'm told, the Sun compiler), put the return
> value of pointer-valued functions in A0 - NOT in D0.  As such, if you don't
> declare "malloc" as returning "char *", its caller will expect the return
> value to be in D0 and will get whatever junk was there last.

The real world is a tough place to live.  We decided we could not afford
to break all the programs written by lazy programmers so even pointer-
valued functions return their result in D0.

Also, we once optimized procedure call/return in such a way that it was
impossible to implement alloca (allocate memory on the stack of the
current procedure, very useful but EXTREMELY implementation dependent).
We also had to remove that as a concession to reality.

Of course, you've never really had lint problems unless you've had to
deal with a word adressed, 24-bit word machine on which

	int i; char *p; p = (char *)&i;

generates more than a simple move instruction!

					Bill Shannon
					Sun Microsystems, Inc.

darryl@haddock.UUCP (02/09/85)

>The Motorola 68000 speaks with forked tongue here.  16 bits is suggested
>by the 16-bit data paths used for non-address arithmetic (2 extra clocks
>for a 32-bit "add", f'rinstance), by the lack of 32-bit multiply or
>divide instructions, and by the 16-bit external bus.  32 bits is suggested
>by the large address space.  There is, thus, a good reason for having
>sizeof(int) == 2 and sizeof(char *) == 4 - speed of execution.  There is
>also a good reason for having them both == 4 - it would be nice to have
>an "int" hold the size of an object larger than 65535 bytes.  There's
>a tradeoff here; depending on your application, either one could be the
>correct choice.
>
>        Guy Harris
>        {seismo,ihnp4,allegra}!rlgvax!guy

I agree with your points, Guy, but I just want to add one more here:  K&R
does say that the difference of two pointers is an INT.  If you want arrays
bigger than 32k-1 elements in your large address space, best to go with 32
bit ints on the 68000.  The draft standard removes this problem by making
the size of the result of a pointer subtractiion implementation-defined.

		--Darryl Richman
		...!cca!ima!ism780!darryl

breuel@harvard.ARPA (Thomas M. Breuel) (02/09/85)

> > [no good reason for sizeof(int)!=sizeof(char *)]
>
> Yes there is!  There is no good reason for you to be too lazy to allow it.
> C is a systems programming language.  I balk at having it bastardized into
> 
> STOP RUINING C FOR SYSTEMS PROGRAMMING.

Exactly. In a systems programming language I expect to have one
(pre-defined) integer type which can hold a pointer. 'C' *is* ruined in
that way that the kind of integer that can hold a pointer is not
pre-defined. This lack is not quite as noticable in 'C' as it is in
Pascal, for example, since you can do arithmetic with pointers easily 
in 'C', without converting them to integers first.

Of course you can 'typedef' such an integer type yourself. I would
prefer the integer type to be an 'int', and I still maintain that that
does not cause significant inefficiencies (being aware of forwarding to
'int' on procedure calles, ...). I would prefer it to be an 'int',
because that is what many programs expect, and because there are
certain notational conveniences extended to the 'int' type. Other
alternatives are to have the compiler pre-declare an integer type
(e.g.  'address') or to allow the programmer to re-declare 'int' to be
*any* integer data type.

> > The way K&R intended (and partially documented it).	
> 
> It isn't clear that they ever intended it to work this way.

Ok, I don't know whether K&R *intended* to work '0' as the nil pointer
on function call. Looking at 'stdio' and at V7 UN*X programs I just
can't help getting that impression, though.

> > While we are on the
> > subject, what about the same treatment for '-1', the (de facto) standard
> > error return value?
>
> Why not say that all integers are mappable to pointers, hey lets do away
> with types at all!

Yes, there should by an integer type such that 

    (AnyPointerType)(AddressIntegerType)(AnyPointerType)(exp)==(exp)

is always true. That's something I expect in a systems programming language. 

Looking at my assembly language programs, I find that I end up doing
95% of all operations with one data type: address (here meant to refer
to the integer type that can hold an address, i.e. 32bits on a 68000).
Maybe 4% are done with characters, and the remaining 1% with other
types. I would be perfectly happy with a systems programming language
that has only one data type: address.  Such languages exist and are
moderately successful. Unfortunatly, they are not widely available in
the UN*X world or on micros.

						Thomas.

guy@rlgvax.UUCP (Guy Harris) (02/09/85)

> 	Does the standard require compilers to generate warnings  when
> they have to generate a cast of function arguments? The potential  for
> truly sloppy coding seems enormous with this change.

No, it doesn't have any such requirement; arguably, it's the same as

	double d;
	int i;

	d = i;

which also requires a coercion.  I see your point that, unlike this case,
where both variables are in the same module and it is assumed that the
program knows what they're doing, programmer A may simply not realize
that the program wants a "double", or may get the number or order of the
arguments wrong, when calling the procedure written by programmer B.

If the coercion "doesn't make sense" (e.g., the routine expects a "struct
frobozz *" and is being passed a "struct death *"), PCC, at least, will
complain (as it currently does with similar assignments).  If the coercion
isn't doable (e.g., the routine expects a "struct frobozz" and is being passed
an "int"), a reasonable compiler will complain and won't generate code.

	Guy Harris
	{seismo,ihnp4,allegra}!rlgvax!guy

guy@rlgvax.UUCP (Guy Harris) (02/09/85)

> 'C' *is* ruined in that way that the kind of integer that can hold a
> pointer is not pre-defined.

I agree 100%.  That's the disadvantage of a language that "jes' growed",
like C (the advantage is that you aren't stuck with incorrect decisions
made when the language was cast in concrete).  The fact that it does
quite well, even given its limitations, is a testimonial to the parts
of C that they got right (C here referring to all post-V6 C's; the C
that came with V6 was inadequate, given the lack of "unsigned" and "long"/
"short" modifiers, etc.).

> > > The way K&R intended (and partially documented it).	
> > 
> > It isn't clear that they ever intended it to work this way.
> 
> Ok, I don't know whether K&R *intended* to work '0' as the nil pointer
> on function call. Looking at 'stdio' and at V7 UN*X programs I just
> can't help getting that impression, though.

K&R didn't write most of that code, and what they did write may have come
before they thought about the nil pointer question.  Heck, they changed
their minds when confronted with new data - "-=" disappeared when it was
realized that "a=-b" was ambiguous (and now "=-" is gone from the language).
Lots of UNIX code has gotten cleaner (at least with respect to type-correctness)
as time has gone on - as of 4.2BSD and System V, the code is lots better.
(A lot of System V looks as if somebody at least tried to "lint" most of the
commands.)

	Guy Harris
	{seismo,ihnp4,allegra}!rlgvax!guy

Doug Gwyn (VLD/VMB) <gwyn@Brl-Vld.ARPA> (02/10/85)

We had a language like the one you are asking for.  It was called "B"
and was sufficiently unsatisfactory that "C" was invented to take its
place.

If you really HAVE to have a known integer type into which a pointer
to anything (there is no such thing as just a "pointer" in C) will
fit, then use (unsigned long).  Surely that will be big enough.  The
whole point of "int" is that it best fits the machine word size, not
that it is capable of holding any address.

ron@brl-tgr.ARPA (Ron Natalie <ron>) (02/11/85)

> 
> Looking at my assembly language programs, I find that I end up doing
> 95% of all operations with one data type: address (here meant to refer
> to the integer type that can hold an address, i.e. 32bits on a 68000).
> Maybe 4% are done with characters, and the remaining 1% with other
> types. I would be perfectly happy with a systems programming language
> that has only one data type: address.  Such languages exist and are
> moderately successful. Unfortunatly, they are not widely available in
> the UN*X world or on micros.
> 

You obvously don't work on a diverse enough collection of machines.
Some machines have readically different types of "address" depending on
the data type. However, several of the propositions by the C standards
will solve these problems.

The bottom line pointer (void *) can replace any need to try to stick
a pointer into an integer.  As you state, a lot of work is done handling
a type called "address."  Well (void *) is an attempt to implement this
witout warping the semantics of the language too much.  In addition, it
wouldn't require any needless restraints on what "int" is just because
pointers are an odd size on this machine.

The other problem involves the use of 0.  Legally you are supposed to
be able to assign the constant 0 to a pointer and compare a pointer to
zero.  But if you try to pass zero to a function expecting a pointer,
it gets passed as int.  The function argument typing will solve this
problem as well.

See, problem solved.  It's been solved, and these language features
were already fought over and accepted.

-Ron

jim@timeinc.UUCP (Jim Scardelis) (02/11/85)

> Indeed? And what about the 8086, or worse yet, 8088? A full pointer
> is a 20 bit address which must be specified by a 32 bit value  (a
> 16 bit offset and 16 bit segment which overlap for all but 4 bits!).
> Add to that the 8088, which has 16 bit registers but does transfers
> 8 bits at a time. What is the "natural" choice for an int on these
> machines, and why should it have anything at all to do with their
> pointer architecture?
> 
> 
> Ken Mitchum
> cadre.ARPA

The 'natural choice' is sixteen bits if you go by the iAPx86 builtin
integer size for mathmatics....but actually that should only hold for
Small memory model programs. The large model programs should really
use a 32 bit int, because of the pointer size...it seems that most of the
C code I've seen assumes that a pointer is an int...

...like the netnews software that I'm having a *devil* of a time getting
up on an IBM PC/AT (80286 chip)...

				Jim Scardelis

-- 
    "The opinions expressed herein are those of my computer, and are not 
		necessarily mine, or those of my employer."
-------------------------------------------------------------------------------
UUCP: {vax135|ihnp4}!timeinc!jim		AT&T: (201) 843-0022 (business)
ARPA: 1891@NJIT-EIES.MAILNET@MIT-MULTICS.ARPA
USNAIL: P.O. Box 244
	Little Falls, NJ 07424-0244
-------------------------------------------------------------------------------

qwerty@drutx.UUCP (Brian Jones) (02/12/85)

I couldn't help but throw in my $.25 worth - K&R, 14.4:

"A pointer may be converted to any of the integral types LARGE ENOUGH TO HOLD
IT.  Whether an int or a long is required is MACHINE DEPENDENT." (Emphasis is
mine)

I am working with a C compiler and an 8086 based system.  I have also found
problems porting programs that are written with non-portable assumptions.

I have begun to wish for data types such as int8, int16, int32, etc. so that
programmers could say what they really mean, instead of leaving it as an
"exercise for the student".

						Brian Jones
						AT&T - Tech
						{ihnp4,}!drutx!qwerty

jack@boring.UUCP (02/20/85)

In article <2023@drutx.UUCP> qwerty@drutx.UUCP (Brian Jones) writes:
>I couldn't help but throw in my $.25 worth - K&R, 14.4:
>
>"A pointer may be converted to any of the integral types LARGE ENOUGH TO HOLD
>IT.  Whether an int or a long is required is MACHINE DEPENDENT." (Emphasis is
>mine)
>
>...
>I have begun to wish for data types such as int8, int16, int32, etc. so that
>programmers could say what they really mean, instead of leaving it as an
>"exercise for the student".
no, No, NO, NO!!!!!
If you use things like 'int16' to store, for instance, the difference
between two pointers, you are just replacing one machine dependency
with another.
Because pointers can only be 2**16 apart on *your* machine does not mean
that this is true for all machines!
What you should have is a 'pointer_diff' type, in which you can store
the difference (signed, probably) between two pointers.

Don't get me wrong, I like the 'int8' idea, but only for storing *normal*
integers, of which the programmer nows that they will allways fit in
8 bits, *not* for storing pointer differences.

(Note that I say 'pointer difference' everywhere. I think this is the only 
legitimate reason for pointer->int conversion. People who store pointers in ints
should be unlink()ed at first sight)
-- 
	Jack Jansen, {decvax|philabs|seismo}!mcvax!jack
Notice new, improved, faster address         ^^^^^

gwyn@brl-tgr.ARPA (Doug Gwyn <gwyn>) (02/21/85)

Re: int8, int32, etc.

Do you also propose int9, int36?  int24?  float48?

Let's not embed machine dependencies into the language!

tmb@talcott.UUCP (Thomas M. Breuel) (02/22/85)

> Re: int8, int32, etc.
> 
> Do you also propose int9, int36?  int24?  float48?
> 
> Let's not embed machine dependencies into the language!

Some real-life programs require minimal sizes for integers and floating
point numbers. 'int8' should be used as an integer type that holds at
least 8 bits, not as a type that holds exactly 8 bits.

If your 'C' compiler does not support 32 bit integer precision, but
my differential equations need 32 bit integers, then that is a problem
with your 'C' compiler, not my equations.

						Thomas.

jon@cit-vax (Jonathan P. Leech) (02/22/85)

> Re: int8, int32, etc.
>
> Do you also propose int9, int36?  int24?  float48?
>
> Let's not embed machine dependencies into the language!

       If I recall  correctly,	the  Mainsail  language  guarantees  a
MINIMUM length range for data types INTEGER, LONG INTEGER, REAL,  LONG
REAL, etc., rather than a specific width.  While this might result  in
inefficiencies on some machines, it makes code machine INDEPENDENT, at
least in this particular area.

    -- Jon Leech
    jon@cit-vax.arpa

gwyn@Brl-Vld.ARPA (VLD/VMB) (02/23/85)

The ANSI C standard will also guarantee minimum sizes for things.

mwm@ucbtopaz.CC.Berkeley.ARPA (02/24/85)

In article <282@talcott.UUCP> tmb@talcott.UUCP (Thomas M. Breuel) writes:
>> Re: int8, int32, etc.
>> Do you also propose int9, int36?  int24?  float48?
>> Let's not embed machine dependencies into the language!
>
>Some real-life programs require minimal sizes for integers and floating
>point numbers. 'int8' should be used as an integer type that holds at
>least 8 bits, not as a type that holds exactly 8 bits.
>
>If your 'C' compiler does not support 32 bit integer precision, but
>my differential equations need 32 bit integers, then that is a problem
>with your 'C' compiler, not my equations.

You pegged int 8 almost exactly (I want it to have 8 bits of magnitude).
Likewise, uint10 should be an unsigned holding 10 bits. So, if I need an
int that holds -511..511, I should declare it as int9. By leaving out that,
you are forcing systems that have 10-bit quantites "naturally" (is BBN
still selling them?) to go to the next size you typedef'ed.

Conclusion: For any machine/compiler pair, there should be a file that
typedefs intX and uintX for all X the machine can use so that you get at
least that many bits. X's to big for the system are left undefined. You may
want two versions, one optimized for space, and one optimized for speed.

As recently suggested, there should also be a point typedef, that is large
enough to hold the difference between two pointers.

The result of using this system is that you know your programs will get
enough space on strange hardware. If it needs things that are too big, it
won't compile.

	<mike

gwyn@brl-tgr.ARPA (Doug Gwyn <gwyn>) (02/24/85)

> The result of using this system is that you know your programs will get
> enough space on strange hardware. If it needs things that are too big, it
> won't compile.

I think this is backwards.  How about writing your code in terms of
parameters describing the system (such as those in <limits.h>), rather
than writing code that does not work on systems having perfectly
reasonable arithmetic properties that just don't happen to be what
you had when you wrote the code.

I see the ANSI C committee is attempting to fix the botched floating-
point parameters in /usr/group's published set of implementation limits.
There are more parameters needed than what they have so far (see the
UNIX System V <values.h> for example).

mwm@ucbtopaz.CC.Berkeley.ARPA (02/26/85)

In article <8567@brl-tgr.ARPA> gwyn@brl-tgr.ARPA (Doug Gwyn <gwyn>) writes:
>> The result of using this system is that you know your programs will get
>> enough space on strange hardware. If it needs things that are too big, it
>> won't compile.
>I think this is backwards.  How about writing your code in terms of
>parameters describing the system (such as those in <limits.h>), rather
>than writing code that does not work on systems having perfectly
>reasonable arithmetic properties that just don't happen to be what
>you had when you wrote the code.

No, that is forwards. If your code needs 34 bit ints, and the system your are
trying to compile it on doesn't support ints that are >= 34 bits in length,
then it isn't going to run. Why bother letting it compile in that case?
Especially when the compile time errors will point to the variables that
cause the problem?

BTW, can I use <limits.h> (we don't seem to have one) to correctly put a
variable that needs 9 bits in a char on a C/70, and in a short on a VAX?

	<mike

gwyn@brl-tgr.ARPA (Doug Gwyn <gwyn>) (02/27/85)

>  If your code needs 34 bit ints ...

How did you get yourself into this jam?

Ints are only guaranteed to cover the range -32767 to +32767.
Not even long ints are guaranteed to have 34 bits of dynamic range.

I have written a lot of C code and NEVER have had any such
word length dependencies (other than in explicitly system-dependent
code that would not make sense to try to port anyway).
I would be interested in why your code has them.

tmb@talcott.UUCP (Thomas M. Breuel) (03/01/85)

> Ints are only guaranteed to cover the range -32767 to +32767.
> Not even long ints are guaranteed to have 34 bits of dynamic range.

Are they?

> I have written a lot of C code and NEVER have had any such
> word length dependencies (other than in explicitly system-dependent
> code that would not make sense to try to port anyway).
> I would be interested in why your code has them.

Well, you obviously have not written code that computes something
to a given degree of accuracy. An example of where I needed 32 bits
(and 16 bits just wouldn't do) was the simulation of a system of
40 non-linear differential equations (the program was written in
68000 assembly language, btw, not in 'C').

						Thomas.

gwyn@Brl-Vld.ARPA (VLD/VMB) (03/01/85)

If you need a guaranteed 32 bits in an integral type in C,
use (long int) a.k.a. (long), NOT (int).  If you need more than
32 bits then you can't portably directly use any C integral
type (although you can accomplish this in other ways).

Anyone who uses (int) and needs more than 16 bits is making a
mistake.