[comp.sources.d] Mea Culpa Re: Something's Broken: was ... Re: tgetent

rwwetmore@grand.waterloo.edu (Ross Wetmore) (07/19/88)

>:  (int)n = (char *)p - (char *)q;

>:  This is perfectly valid 'C'
>	Read about casting lvalues again.
>:                              and will never to my knowledge be picked
>:up by any lint program.

  Right this was never intended to be a cast :-). While I might have
gotten away with 'int n = (char *)p - (char *)q;' what I really should
have done is made all the definitions explicitly, and avoided trying
to squish things down to a single line or at least been a little more
careful to double check what I had written as opposed to thought.
  My apologies for the confusion this may have caused.

  Moral: always use lint and spell on mail messages before posting :-)

>:  The fact that NULL, defined as the integer constant 0, is explicitly
>:defined to be a valid null pointer on assignment (but not generally, 
>:which is what caused the original problem) only reinforces the linkage.
>No, (char *) NULL is the null pointer. 0 is 0. If you don't believe
>that, I bet a lot of your 68000-based code crashes for no apparent 
>reason.

  From the first line on pg 97 of K&R ...

#define NULL  0  /* pointer value for error report */

  QED. Your comment on 68K code crashing only reinforces my point.

>When talking about portable code, you had better
>be planning to recognize the difference between a pointer and an
>integer or you had better plan on spending late nights wondering
>why your code keeps falling over. It's that simple --- K&R say a
>pointer is a pointer and an integer is an integer and they may be of
>different size. Live with it. 
>-david-

  K&R also says that the result of pointer arithmetic is an int. And
any implementation of standard C functions I have ever seen has things
like strlen(), sizeof() ... returning an int-sized value. Note that
lseek() which refers to disk addresses returns a long (ie the largest
possible integer size on the machine).
  While pointers and ints are declared to be of different sizes, somehow 
the size of an int and a pointer are still linked by such constructs.
This means that pointer code which runs fine on a 32-32 machine fails 
inexplicably on a 32-16 machine where the only diifference in the
machines is changing the size of an int from 32 to 16. 

>So, if my ints are 32 bits and my pointers 64, I am not running K&R
>C? Nonsense!

  No, I never said that. The correct conclusion was what my original
posting gave in counterpoint to the previous claim that an architecture
was broken if such code failed. The conclusion was that one could not
fault the architecture or compiler, and if anything was broken it was
the language specifications that permitted or dictated such 
inconsistencies. In fact the Intel architecture commented on enforces
strict conformance with K&R in the hardware.

  I like C just fine, and prefer it to many other languages I use, but
this still does not mean I have to be bashful about its shortcomings
either those explictly recorded in K&R or those carefully not recorded
there. I still think C works best on machines where pointers and ints
are the same size :-)

Ross W. Wetmore                 | rwwetmore@water.NetNorth
University of Waterloo          | rwwetmore@math.Uwaterloo.ca
Waterloo, Ontario N2L 3G1       | {uunet, ubc-vision, utcsri}
(519) 885-1211 ext 3491         |   !watmath!rwwetmore

chris@mimsy.UUCP (Chris Torek) (07/23/88)

In article <19964@watmath.waterloo.edu> rwwetmore@grand.waterloo.edu (Ross
Wetmore) writes:
>>:  The fact that NULL, defined as the integer constant 0, is explicitly
>>:defined to be a valid null pointer on assignment (but not generally, 
>>:which is what caused the original problem) only reinforces the linkage.
[between pointers and integers]

It may have been a design mistake, but it is not a fatal one.

[someone else, name forgotten:]
>>No, (char *) NULL is the null pointer.

There is no `the null pointer': there are an infinite variety of nil
pointers.  (char *)NULL is `the nil pointer to char', and nothing else.
There are many machines on which `char *' pointers have more bits, or
have bits in different places, than other pointers; there is at least
one machine on which pointers to functions are nine times longer than
pointers to data.  From this it is easy to see why the proper cast is
required: any other cast may give you the wrong number of bits, or the
right number of bits but in the wrong order.

>  K&R also says that the result of pointer arithmetic is an int.

Rather, that the result of pointer *subtraction* is an int.  In the
draft proposed American National Standards C Standard X3J11, the
result is defined as an object of type `ptrdiff_t', which is simply
a signed integral type (and hence may be `long' rather than `int').
This, along with `size_t', removes the existing restriction that any
single object may not be larger than an int-worth.

>  While pointers and ints are declared to be of different sizes, somehow 
>the size of an int and a pointer are still linked by such constructs.
>This means that pointer code which runs fine on a 32-32 machine fails 
>inexplicably on a 32-16 machine where the only diifference in the
>machines is changing the size of an int from 32 to 16. 

Only if (assuming a byte-addressed machine) objects on the 32-16 machine
are allowed to span more than 65536 bytes, and only under K&R rules, not
under the dpANS rules.  Note that so-called `huge model' compilers for
the IBM PC use rules closer to those in the dpANS (so that they will be
useful).

>I still think C works best on machines where pointers and ints
>are the same size :-)

Certainly lazily-written C code works best on machines where this is
true (and where pointers are untagged and everything is byte-addressed).
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

allbery@ncoast.UUCP (Brandon S. Allbery) (08/02/88)

As quoted from <19964@watmath.waterloo.edu> by rwwetmore@grand.waterloo.edu (Ross Wetmore):
+---------------
| >:  The fact that NULL, defined as the integer constant 0, is explicitly
| >:defined to be a valid null pointer on assignment (but not generally, 
| >:which is what caused the original problem) only reinforces the linkage.
| >No, (char *) NULL is the null pointer. 0 is 0. If you don't believe
| >that, I bet a lot of your 68000-based code crashes for no apparent 
| >reason.
| 
|   From the first line on pg 97 of K&R ...
| 
| #define NULL  0  /* pointer value for error report */
| 
|   QED. Your comment on 68K code crashing only reinforces my point.
+---------------

And in the middle of page 98, discussing the same code...

"Any pointer may be meaningfully compared for equality or inequality with
NULL.  But all bets are off if you do arithmetic or comparisons with pointers
pointing to different arrays.  If you're lucky, you'll get obvious nonsense
on all machines.  If you're unlucky, your code will work on one machine but
collapse mysteriously on another."

Sounds like K&R disagree with you....

+---------------
|   K&R also says that the result of pointer arithmetic is an int. And
+---------------

Where, pray tell?

+---------------
| any implementation of standard C functions I have ever seen has things
| like strlen(), sizeof() ... returning an int-sized value. Note that
+---------------

A bad habit, it should properly be something like memsize_t which on many
BUT NOT ALL machines may be (int).  (Compare large-model 80286 where strlen()
may conceivably have to return a (long), and it will break! because of the
cavalier attitude toward pointer/integer conversion held by many programmers.)

Before you start in about how it's standard so it must be right, tell me how
many Berkeley programs assume that *((char *) 0) == '\0' instead of following
the rule that that address is supposed to be outside the process's address
space?

+---------------
| fault the architecture or compiler, and if anything was broken it was
| the language specifications that permitted or dictated such 
| inconsistencies. In fact the Intel architecture commented on enforces
| strict conformance with K&R in the hardware.
+---------------

First you say the language specs are broken, then you say they are correct?
Or are you trying to pass the old "all the world's a VAX" argument to us
under new guise?  I refuse to believe that C is *supposed* to be Vax-only,
I prefer to believe K&R.

+---------------
| there. I still think C works best on machines where pointers and ints
| are the same size :-)
+---------------

I think C works best when you use it properly.  Funny, but when you *do* do
so, your programs will run anywhere.

Please note that without some means of getting the proper sizes of things,
the compiler *cannot* make the right decisions -- it can't read your mind
to find out that strlen() takes a (char *), it has to have ANSI prototypes
added so you can tell it about "memsize_t strlen(const char *)".  --And
please note the type I used, having it return (int) is identical to all the
other pointer/integer problems we've been discussing.  This *is* a short-
coming, but if you cast things to work around it things work fine.

I use C with the assumption that that is the way things are supposed to work;
given the possibility of "varargs" functions, not even ANSI prototyping will
solve all your problems.  Consider `execl("/bin/foo", "foo", "bar", 0)'
under 80286 large model.  You can't describe it under ANSI prototypes -- or
any other prototyping system unless you put so many constraints on function
arguments that e.g. printf() won't work any more.  And it will assuredly
drop core.  C *requires* that you specify the argument types because it
allows you to have functions change their expected argument lists on the fly
(compare printf again).  Moreover, done correctly according to the language
rules varargs *does* seem to work on all systems -- because of this
wonderful generality.

++Brandon
-- 
Brandon S. Allbery, uunet!marque!ncoast!allbery			DELPHI: ALLBERY
	    For comp.sources.misc send mail to ncoast!sources-misc