[comp.lang.c] "for" loops in C ...

limes@ouroborous (Greg Limes) (10/18/88)

In article <6945@cdis-1.uucp>, tanner@cdis-1 (Dr. T. Andrews) writes:
>It is also possible that compiler writers will get the "for" loop
>handling wrong.  It is unwise to depend on "for" loops in portable
>code.  Use a "while" loop instead.

It is possible for compiler writers to get lots of things wrong; breaking
something as fundamental as a "for" statment results in an unusable
compiler. It is, well, kind of basic to the language.

Dr. Andrews, can you provide an example of a compiler in common use that
manages to get the for loop wrong? I will gladly make a note of such and stay
away from them (and any other software produced by their writers).

Portability usually includes such wild concepts as readability and
maintainability (at least in my mind), and a properly organized "for" loop
becomes a bit more opaque when reduced to a "while".
-- 

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

In article <73408@sun.uucp> limes@ouroborous (Greg Limes) writes:
| In article <6945@cdis-1.uucp>, tanner@cdis-1 (Dr. T. Andrews) writes:
| >It is also possible that compiler writers will get the "for" loop
| >handling wrong.  It is unwise to depend on "for" loops in portable
| >code.  Use a "while" loop instead.
| 
| It is possible for compiler writers to get lots of things wrong; breaking
| something as fundamental as a "for" statment results in an unusable
| compiler. It is, well, kind of basic to the language.
| 
| Dr. Andrews, can you provide an example of a compiler in common use that
| manages to get the for loop wrong? I will gladly make a note of such and stay
| away from them (and any other software produced by their writers).

Didn't anyone else see what Dr. Andrews was pointing out?  Saying that
you should avoid the construct 1["string"] is *like* saying you should
avoid a for loop, because both are fundamental constructs that a broken
C compiler may not implement correctly.  Avoiding something fundamental
just because some compiler somewhere gets it wrong is no excuse -- FIX
THE COMPILER.


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

limes@ouroborous (Greg Limes) (10/20/88)

In article <6945@cdis-1.uucp>, tanner@cdis-1 (Dr. T. Andrews) writes:
>It is unwise to depend on "for" loops in portable
>code.  Use a "while" loop instead.
 
In article <73408@sun.uucp> limes@ouroborous (Greg Limes) writes:
>Dr. Andrews, can you provide an example of a compiler in common use that
>manages to get the for loop wrong?

In article <23299@amdcad.AMD.COM>, tim@crackle (Tim Olson) writes:
>Didn't anyone else see what Dr. Andrews was pointing out?  Saying that
>you should avoid the construct 1["string"] is *like* ...

I may have put my foot in the middle of that one, but maybe not. On the other
hand, it is easier to simply say that I was asleep at the keyboard, then to
point out the basic difference between getting a "for" construct wrong
(something basic to the language and hard to get wrong) in a compiler, and
failing to support subscripting an integer by a pointer (something a bit less
basic, and in fact rather arcane, that may fall by the wayside if there are a
lot of complex issues about pointers).

So, sorry for being asleep at the keyboard.
-- 
Greg Limes [limes@sun.com]		semper ubi, sub ubi

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

In article <23299@amdcad.AMD.COM> tim@crackle.amd.com (Tim Olson) writes:

| Didn't anyone else see what Dr. Andrews was pointing out?  Saying that
| you should avoid the construct 1["string"] is *like* saying you should
| avoid a for loop, because both are fundamental constructs that a broken
| C compiler may not implement correctly.  Avoiding something fundamental
| just because some compiler somewhere gets it wrong is no excuse -- FIX
| THE COMPILER.

  I would suggest that there is a very good reason to avoid int[ptr],
being that it's hard to read. Obviously it's part of the language, but
is there any reason to use it other than to prove how well you
understand C? That's real question, I would be pleased to learn that
there really is some benefit, but I don't see much between int[prt],
ptr[int] and *(ptr+int) other than readability.

  Obviously "string"[int] is legal, too, but somewhat less than readable
to the casual programmer.
-- 
	bill davidsen		(wedu@ge-crd.arpa)
  {uunet | philabs}!steinmetz!crdos1!davidsen
"Stupidity, like virtue, is its own reward" -me

ts@cup.portal.com (Tim W Smith) (11/01/88)

I don't know about i[ptr] being less readable than ptr[i].  Most people I
have heard would say when describing an algorithm in English, "Then you take
the ith element of the array and multiply by foo".  i[array]*foo has the
words in C in the same order they would be spoken.

						Tim Smith

hjm@cernvax.UUCP (Hubert Matthews) (11/04/88)

In article <10742@cup.portal.com> ts@cup.portal.com (Tim W Smith) writes:
>I don't know about i[ptr] being less readable than ptr[i].  Most people I
>have heard would say when describing an algorithm in English, "Then you take
>the ith element of the array and multiply by foo".  i[array]*foo has the
>words in C in the same order they would be spoken.
>
>						Tim Smith


Take a look at Knuth.  He uses a notation like next(a) to represent the
C statement a.next.  His argument goes something like this.  The
function next() is applied to a variable argument - next(a) or next(b)
- just like good ol' array indexing in FORTRAN - array(i).  Well, why
not?  BCPL made it very obvious that a[i] and i[a] are the same; it
used (uses?) a!i to mean *(a+i).  This works fine even for structure
access, until you have strong typing.  Guess what BCPL didn't have?  I,
personally, IMHO, would be happy with a[next] for structure access or
a.i for array access.  Isn't it all really the same and just a matter
of conditioning?  As I said, it's not obvious how strong typing would
work in such a language, but it would eliminate one more thing for the
compiler writers to have to do *and get right*. :-)

-- 

	Hubert Matthews

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

In article <867@cernvax.UUCP> hjm@cernvax.UUCP (Hubert Matthews) writes:
>I personally, IMHO, would be happy with a[next] for structure access or
>a.i for array access.  Isn't it all really the same and just a matter
>of conditioning?  As I said, it's not obvious how strong typing would
>work in such a language, but it would eliminate one more thing for the
>compiler writers to have to do *and get right*. :-)

In POP, arg.fn and fn(arg) are merely syntactic variants, so one can
write	record.field -> array(subscript);
or	field(record) -> subscript.array;
and it's all the same thing.  How would string typing work?  Just like
it always did: the information comes from the (bindings of) the
identifiers, not the punctuation marks.

dsb@Rational.COM (David S. Bakin) (11/09/88)

[What's going on?  The article I'm replying to was signed by Chris Torek of
 uunet!mimsy!chris but the headers say it is from ok@quintus.uucp???]

In article <645@quintus.UUCP>, ok@quintus (Richard A. O'Keefe) writes:
>In article <192@libove.UUCP> root@libove.UUCP (Jay M. Libove) writes:
>>Looking at the above, I read it to be "shift an n-bit integer n bits left"
>>... Now, why is there any question as to the result?
>
>Because different machines implement shift-left differently.
>
> ... [omitted]
>
>On the VAX, the result of shifting by the (not known to be constant)
>value 32 is the same as the result of shifting by zero, because the VAX
>looks only at the 5 lowest order bits of the shift count.  It does this
>so that right shifts can be done with negative left shifts.
>-- 
>In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
>Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

I don't get it.  The operator << is defined in C as a left shift, what
does that have to do with a particular VAX instruction, ASHL, that happens
to mask its operand to the low-order 5 bits.  Doesn't this merely mean that
on the VAX when the argument of the left shift is not a known constant that
the single instruction ASH sequence must be replaced by a multiple instruction
sequence that does the right thing?

-- Dave

----------------------------------------------------------
Dave Bakin				    (408) 496-3600
c/o Rational; 3320 Scott Blvd.; Santa Clara, CA 95054-3197
Internet:  dsb@rational.com	 Uucp:  ...!uunet!igor!dsb

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

In article <339@igor.Rational.COM> dsb@Rational.COM (David S. Bakin)
continues asking about "<<".
>The operator << is defined in C as a left shift, ...

Nope.  << is defined to be whatever C defines it to be, and C leaves it
as vague as possible to make it easy for compiler writers to generate
fast code.  (There is something just slightly crazy about this.)  It has
nothing to do with the VAX as such.  We can define shifting for signed
integers as
	X << Y = floor(X * 2**Y)
which definition works beautifully for all values of X and Y.  Alas,
that's not what the hardware does on _any_ machine that I know of (the
VAX comes *closest*.)  Some machines take the bottom 5 bits.  Some take
the bottom 6.  Some haven't _got_ a left shift instruction.  (For
example, on the M88000, the simplest translation of X<<Y yields the
result X&1 when Y==32.)

If you want to make sure that you will get the result you expect,
define BITS_PER_BYTE suitably and write
	result = Y >= BITS_PER_BYTE*sizeof X ? 0 : X>>Y;
(assuming that you are happy to have result undefined when Y < 0).

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

In article <339@igor.Rational.COM> dsb@Rational.COM (David S. Bakin) writes:
>I don't get it.  The operator << is defined in C as a left shift, what
>does that have to do with a particular VAX instruction, ASHL, that happens
>to mask its operand to the low-order 5 bits.  Doesn't this merely mean that
>on the VAX when the argument of the left shift is not a known constant that
>the single instruction ASH sequence must be replaced by a multiple instruction
>sequence that does the right thing?

The point is precisely that one would prefer to avoid this, for the sake
of (whisper it) efficiency.  There are quite a number of places where the
semantics of C are deliberately machine-specific, to permit implementors
to do things the most efficient way rather than having to take a performance
hit from doing them a standard way.  Such flexibility is generally made
available either because the efficiency impact of not doing so is major
(e.g. size of int) or because the semantics appear to be unimportant for
well-written programs (e.g. the order of side effects in an expression).
Shift counts equal to the word size are generally considered a case of
the latter, with some of the former stirred in.
-- 
The Earth is our mother.        |    Henry Spencer at U of Toronto Zoology
Our nine months are up.         |uunet!attcan!utzoo!henry henry@zoo.toronto.edu

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

 >I don't get it.  The operator << is defined in C as a left shift, what
 >does that have to do with a particular VAX instruction, ASHL, that happens
 >to mask its operand to the low-order 5 bits.  Doesn't this merely mean that
 >on the VAX when the argument of the left shift is not a known constant that
 >the single instruction ASH sequence must be replaced by a multiple instruction
 >sequence that does the right thing?

More precisely, "<<" is defined as a left shift that does unspecified
things if the shift count is larger than the size of the (appropriately
promoted) left-hand operand.  Thus, the single VAX ASHL instruction
implements what various language specs say "<<" means, and a left-shift
instruction that *didn't* mask the shift count would also do so.

smryan@garth.UUCP (Steven Ryan) (11/10/88)

>- just like good ol' array indexing in FORTRAN - array(i).  Well, why
>not?  BCPL made it very obvious that a[i] and i[a] are the same; it

To an optimiser in a language with real arrays, they are not the same.

In such languages, lwb a<=i<=upb a so that the location is constrained
to the region labeled a. This permits optimisers to make assumptions about
whether two memory references can interfere.

>used (uses?) a!i to mean *(a+i).  This works fine even for structure
>access, until you have strong typing.  Guess what BCPL didn't have?  I,
>personally, IMHO, would be happy with a[next] for structure access or
>a.i for array access.  Isn't it all really the same and just a matter

How would you parse that? Fields and subscripts have different syntax,
although the concept are similar, to make context-free parsing possible.
-- 
                                                   -- s m ryan
--------------------------------------------------------------------------------
As loners, Ramdoves are ineffective in making intelligent decisions, but in
groups or wings or squadrons or whatever term is used, they respond with an
esprit de corps, precision, and, above all, a ruthlessness...not hatefulness,
that implies a wide ranging emotional pattern, just a blind, unemotional
devotion to doing the job.....

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

In article <1811@garth.UUCP> smryan@garth.UUCP (Steven Ryan) writes:
>>personally, IMHO, would be happy with a[next] for structure access or
>>a.i for array access.  Isn't it all really the same and just a matter
>
>How would you parse that? Fields and subscripts have different syntax,
>although the concept are similar, to make context-free parsing possible.

Some languages use different syntax for fields and arrays, just as
some languages (e.g. C, Pascal, Algol) use different syntax for arrays
and other functions and some (e.g. Fortran, ADA) don't.  Context-free
parsing has nothing to do with the case.  In the usual mathematical
model of records, "fields" are projection FUNCTIONS.  That is, given
	type node = (data: int, next: link)
we have two functions data: node->int, next: node->link.  And an array
is a function which maps its index set to its element set, e.g.
	var data: array[node] of int;
	    next: array[node] of link;
Whether one writes
	n.data		"field"
	data[n]		"array"
	data(n)		"function"
is a matter of taste.  You have to check "data" in the symbol table anyway,
to make sure that it is a valid field name (or array name, or function
name).  Some people like to think of fields, arrays, and functions as
distinct, and prefer a notation which makes that explicit.  Some people
like to think of them all as functions, and prefer a notation which lets
them change the implementation without having to rewrite all their code.

Have you never found it frustrating that C will let you write macros that
look like functions, but not macros that look like arrays or fields?

dsb@Rational.COM (David S. Bakin) (11/11/88)

Well I've read several responses to my innocent and IMHO reasonable 
"assertion" that C's << operator was a left shift.  All pointed out
that it is a machine-dependent left shift and deliberately so in the
name of efficiency.

This means two things to me.  First, I have to reread the C manuals
I have verrry carefully.  And second, my original opinion was right:
C is no more than an assembly language with extra whitespace and
slower language translators.  :-)

-- Dave

----------------------------------------------------------
Dave Bakin				    (408) 496-3600
c/o Rational; 3320 Scott Blvd.; Santa Clara, CA 95054-3197
Internet:  dsb@rational.com	 Uucp:  ...!uunet!igor!dsb

chris@mimsy.UUCP (Chris Torek) (11/11/88)

In article <342@igor.Rational.COM> dsb@Rational.COM (David S. Bakin) writes:
>Well I've read several responses to my innocent and IMHO reasonable 
>"assertion" that C's << operator was a left shift.  All pointed out
>that it is a machine-dependent left shift and deliberately so in the
>name of efficiency.
>
>This means two things to me.  First, I have to reread the C manuals
>I have verrry carefully.  And second, my original opinion was right:
>C is no more than an assembly language with extra whitespace and
>slower language translators.  :-)

To some extent, yes.  But this is true of most languages.  There are
remarkably few languages in which `*' (or whatever the local symbol may
be) *really* means `multiply', for instance.  It usually means `choose
the appropriate MUL instruction/subroutine and let the chips fly where
they may'---often into the bit bucket.  There are a number of languages
where

	for i:integer from 0 to 60000 do ... rof

runs forever on a 16-bit machine.  This deviation from the
`mathematically proper' behaviour is virtually always done for
`efficiency'.  There is often some attempt at allowing runtime error
checking (via, e.g., exceptions), but it is also often weak (which
arithmetic exceptions are *guaranteed* in Ada? PL/I?).

There *are* languages in which `*' really means `multiply'.  One of
these is even old enough for most people to have heard of it :-)
---Lisp.  If you multiply big numbers, you get back a bignum, not an
overflow.  If you shift n left s, you get n times two-sup-s.  You also
pay a penalty in efficiency---so much so that the local Lisp dialect
usually provides an `I think this cannot overflow so use the MUL
instruction' variant.  Type-inferencing (and range-inferencing)
languages or compilers sometimes do this for you in `safe' ways.  More
of these sorts of languages are appearing all the time.  These are
the real `high level' languages.  They are still largely pure research
vehicles.

Languages of the other sort, including C, Pascal, Modula, FORTRAN,
etc., are designed as a compromise between `what the machine really
does' and `what abstractions programmers would like the machine to
do'.  The real differences between `low' and `high' level languages are
not in their syntaxes, but rather in how well they insulate the
programmer from the shocks found down on the bare metal.  The
insulation is sometimes quite thin, and it is your job as a programmer
to know exactly where and how much.  When you said:

>... I have to reread the C manuals I have verrry carefully.

you were right.  You should have done that earlier (but with the dpANS
you will have to do it again anyway---some of that insulation has been
moved around).

If you write anything more than toy programs, know your languages'
weak spots.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

john@frog.UUCP (John Woods) (11/14/88)

In article <14488@mimsy.UUCP>, chris@mimsy.UUCP (Chris Torek) writes:
> In article <342@igor.Rational.COM> dsb@Rational.COM (David S. Bakin) writes:
> >... I have to reread the C manuals I have verrry carefully.
> 
> you were right.  You should have done that earlier (but with the dpANS
> you will have to do it again anyway---some of that insulation has been
> moved around).
> 
I thought I felt a Draft in here...
-- 
John Woods, Charles River Data Systems, Framingham MA, (617) 626-1101
...!decvax!frog!john, john@frog.UUCP, ...!mit-eddie!jfw, jfw@eddie.mit.edu

Science does not remove the TERROR of the Gods!