[net.lang.c] Orphaned Response

knowles@ccvaxa.UUCP (06/24/83)

#R:ccvaxa:8800003:ccvaxa:8800006:37777777600:353
ccvaxa!knowles    Jun 22 21:19:00 1983

Thanks to those who alerted me to a C test suite in the
possession of uiucdcs!richards (parsec!kolstad and parsec!fuka).

We acquired the suite and have used it. Compiler people here
say that its pretty good as far as it goes. Note that parsec!fuka
also has a copy of the suite.

Frankly, I'm surprised that this is the only suite that has
surfaced....

suitti@CSvax:Pucc-H:pur-phy.UUCP (09/09/83)

My comment:
	You can eliminate the "cracks", within structures:
	If you assume that the order of items within a structure may be
	left to the compiler, then the compiler may sort the items into
	longest first.

The reply:
	What you have, then, is not C-as-we-know-it. "Within a structure, the
	objects declared have addresses which increase as their declarations
	are read left-to-right."  Removing that requirement would make life
	difficult for those of us who, for instance, read foreign (non-Unix)
	tapes directly into C structures, relying on the defined alignment
	of structures.

My answer:
	Unless I looked at both machines's compilers carefully,
and didn't really expect people to do this everywhere my programs
were likely to be ported, I would never require that info
sent/recieved would be in the structur's binary form.  For
instance, the binary byte order of a long is differant on a
pdp-11 than a Vax!  That blows that idea.  How much more so is
the whole structure likely to be differant?  A related note, I've
seen non-portable code of longs being played with using chars in
several programs:  The Gosling's EMACS info database routines
for one.
	I re-read chapter 6 (structures) of K & R.  There was no
explicit statement that structure members would be in any order.
When talking about the size of a structure it says: "But don't
assume that the size of a structure is the sum of the sizes of
it's members - because of alignment
requirements for different objects, there may be "holes" in a structure."
(chapter 6, page 130).  It doesn't say how big the holes would be, etc.
	I can only think of one program on my system that would stop working
if I hacked on the C compiler to sort by sizes (more on sorting later).
That's the kernel.  Structs are often used in device drivers to simplify the
syntax of getting at all the various registers that the device has.  There
are a couple of fixes for that too.

More comments:
	It would also make life more difficult when you
	decide to change a structure -- if you add a new object to an existing
	structure declaration you can simply read the old structure into
	the new one, set the value of the added object, and write it out
	again (you just specify different lengths on the read and write).

More reply:
	This can be risky at best, and of limited use.  If one has an
array in the middle of a structure, expanding it or contracting it is
going to upset things.  This is one of the most common structure mods
that I experience.  Under my compiler (the Ritche v7 compiler), adding
(or subracting) stuff at the end of the structure would be relatively
safe.  I prefer my programs to keep their data in ASCII while on disk,
at least, they should have that capability.  For one, it is easier to
debug a clear-text data file.  (I know, you never make mistooks).

More comment:
The whole scheme proposed also founders if objects within the structure
do not have power-of-two lengths. If your structure contains a char[3]
object, sorting it between length 4 and length 2 is not going to
eliminate the need for an alignment byte.

More reply:
I should have thought more about the sorting procedure.  The key
to sorting should be the ls (least significant) bits of each
"sizeof object".  Start with those elements that have (for
instance) their 3 ls bits zero.  Then follow those objects with 2
ls bits, then with one zero ls bit, then the odd sized ones.
Care should be taken that the sort is stable, that is, a structure
will be sorted the same every time, so that separate compilation
will still work.
	The UNIX kernel device driver's structures can be fixed
in three ways.  The first way is not to use structures for this
purpose.  The effort here would be unreasonable.  There are many,
many device drivers on many, many machines.  The second fix is
to have a command line switch to preserve order always.  That way
only the device drivers in the kernel need have "space - inefficient"
structures.  The third way is to leave structures alone that would
not have holes in them as defined.  This is probably safe.  Device
drivers use structures that have been carefully laid out.  I doubt if
there are any holes there anyway.
	I like the compile line switch, in general, for non-standard
features.  For instance, I wouldn't mind one for using single precision
floating point for single precision.  This can also be worked out.

Stephen Uitti (physics site manager)
...pur-ee!Physics:suitti
...purdue!Physics:suitti

tll@druxu.UUCP (09/11/83)

The order of structure members is NOT arbitrary.  The compiler must
retain the order you specified.

	"Within a structure, the objects declared have addresses which
	increase as their declarations are read left-to-right."
				(C Reference Manual, p. 196)

	"Two structures may share a common initial sequence of
	members; that is, the same member may appear in two
	different structures if it has the same type in both
	and if all previous members are the same in both."
				(C Reference Manual, p. 197)

This feature is used by many programs, and I don't think that
closing the holes in a structure is worth removing this feature.

Since compilers are not supposed to support == on structures, why
doesn't a compiler give an error when you try instead of generating
buggy code?

				Tom Laidig
				AT&T Information Systems
					Laboratories, Denver

franka@tekcad.UUCP (09/12/83)

#R:wateng:-27500:tekcad:17800003:000:586
tekcad!franka    Sep 11 12:38:00 1983

	Only certain machines REQUIRE allignment bytes (IBMs and PDP-11's
spring immediately to mind). For example, int's and double's are alligned
in VAX C only because of efficiency reasons. The hardware will fetch non-
alligned data on certain machines (with an efficiency loss). Allignment of
operands is not part of the language design, but only part of machine con-
siderations. I would not say that the allignment of data is a reason not
to allow rearrangement of structures, but having a consistent way to know
where things are put is.
					Frank Adrian
					(tektronix!tekcad!franka)

preece@uicsl.UUCP (09/13/83)

#R:pur-phy:-91000:uicsl:6400009:000:3436
uicsl!preece    Sep 12 08:56:00 1983

Further comments on altering the order of structure elements to
eliminate alignment padding.

				 I would never require that info
	sent/recieved would be in the structur's binary form.  For
	instance, the binary byte order of a long is differant on a
	pdp-11 than a Vax!  That blows that idea.
---
Yes, it's a pain to have to worry about things like the byte order
in longs. On the other hand, if the structure is long enough and
has enough individual elements, it may be faster to explicitly change
the byte order in the longs and use the rest of the structure. We
recently had to read tapes carrying twenty different bibliographic
databases, each in a different format, each consisting of records
averaging perhaps a thousand bytes making up about twenty strings,
forty longs, and various fixed location elements. The tapes ranged
from 100K up to 10M records. Knowing the layout of the record structures
we could manipulate only those parts that (1) we needed to use and (2) were
not in the expected byte order. Having to copy the structures one element
at a time would have been much slower, less clear, and would not have
helped at all with the byte-order problem (some of the data on some of the
tapes was in binary).
---
		I re-read chapter 6 (structures) of K & R.  There was no
	explicit statement that structure members would be in any order.
---
My quote is from page 196 (section 8.5 of the C Reference Manual,
Appendix A of K&R). "Within a structure, the objects declared have
addresses which increase as their definitions are read left-to-right."
Seems unequivocal.
---
	I prefer my programs to keep their data in ASCII while on disk,
	at least, they should have that capability.  For one, it is easier to
	debug a clear-text data file.  (I know, you never make mistooks).
---
I prefer to use ASCII files, too, when it's reasonable to do so. But
sometimes it's not reasonable to do so. If you're dealing with a lot of
numeric data it's not awfully efficient to be continually translating from
ASCII back into binary. And efficiency is still sometimes an issue --
both because (at our site, at least) the machine is not free and because
wall time is sometimes an issue. Ease of debugging is not the only thing
that has to be considered, nor does the use of stored structures make
debugging that much harder -- in our experience those structures are
sometimes EXAMINED during debugging, but are rarely CHANGED by hand during
debugging, so all you need is a simple filter to print out the contents
of the file, in most cases.
---
						The second fix is
	to have a command line switch to preserve order always.  That way
	only the device drivers in the kernel need have "space - inefficient"
	structures.  The third way is to leave structures alone that would
	not have holes in them as defined.  This is probably safe.  Device
	drivers use structures that have been carefully laid out.  I doubt if
	there are any holes there anyway.
---
I could live with the command line option, though I'd make the current
way the default to preserve compatibility with all the existing Unix
programs in the world. The other idea is worse than the existing way,
since it means that structures could be one way or the other. This could
be painful in transporting software from one machine to another or in
debugging after changing a structure definition.
----------
scott preece
uiuc -- coordinated science lab
pur-ee!uiucdcs!uicsl!preece

preece@uicsl.UUCP (09/22/83)

#R:wateng:-27500:uicsl:6400010:000:1049
uicsl!preece    Sep 21 08:09:00 1983

Structure comparison can be very useful, but the nature of the
comparison is almost always not simple enough to be handled by a built-in
capability (except in the one case of testing for absolute equality).
I would not want C to acquire abstract types with operations, but that's
what you need if you want to have general structure operations. I
wouldn't mind having a test for exact match of all named elements of
structures included in C and I wouldn't mind having a structure
assignment operation that set all named elements equal; both features
would sometimes be useful and would involve only modest compiler
effort. But I wouldn't say it was a very important gain, since we can
write the tests explicitly or write them once and call them as a function.
The ability to define exactly what we want comparisons of structures
to do (whether we overload the existing relational operators or
provide some other mechanism) would be very useful, but it doesn't
fit into the texture of C, which is simplicity.

scott preece
pur-ee!uiucdcs!uicsl!preece

keesan@bbncca.ARPA (Morris Keesan) (09/29/83)

The C Reference Manual, as published in "The C Programming Language", by
Kernighan and Ritchie, does indeed say (p. 197), "Two structures may share a
common initial sequence of members . . . if . . . the same type in both and if
all previous members are the same in both."
    HOWEVER, the revised C language, as of UNIX* System V, says (p. 92 of
"Programming Guide UNIX* System), "The names of members and tags do not conflict
with each other or with ordinary variables," and the System V "Transition Aids"
says, in "User Level Changes to the C Language", "The C language has been
revised to permit the reuse of structure members or field names," and also
enforces strict type checking with regard to use of structure member names,
including complete qualification of names.
    Given these changes, there is no need within the C language, i.e. in
programs written only in C, for the preservation of the order of structures.
The requirement for that is due to the nature of C as a system programming
language, which must be able to interface with various operating systems, 
system services, and other languages, and must be able to create control

notes@ucbcad.UUCP (10/06/83)

#R:utzoo:-317600:ucbesvax:4800023:37777777600:702
ucbesvax!turner    Sep  6 03:19:00 1983

Bravo, Mr. Spencer!  Some years ago, when I was stuck on an RT-11 system,
developing a graphics package, I inadvertently came to the same conclusion.
With nothing but FORTRAN to use, and having been given Pavlovian anti-GOTO
treatment in my introductory programming courses, I sought to minimize the
use of GOTO by simply defining new procedures for use in "then" clauses,
whenever these happened to be multi-line.  (For "if...then...else", this
didn't work, of course.)  After a while, the code seemed to be restructuring
itself to be more legible (at least to me.)

If anything, C has gotten me OUT of this good habit.  Well, I can't really
blame the language for creeping vices...

	Michael Turner 

bhyde@inmet.UUCP (01/24/84)

#R:vaxine:-15200:inmet:5000010:177600:1150
inmet!bhyde    Jan 22 17:25:00 1984


This will work; f1, f2, and f3 are necessary.  Of course I didn't want
to have f1, f2, and f3, but then it occurs to me that this isn't Ada
and suddenly I am happy.
						Ben Hyde, Intermetrics Inc.

typedef int elem;  		/* An element				     */
typedef elem feature_vec[];	/*   held in an array     		     */
typedef feature_vec *features;	/*	with pointers to those arrays        */
typedef features ftable[];	/*         which are themselfs in an array.  */

feature_vec f1 = {1,2,2,0};
feature_vec f2 = {2,3,0};
feature_vec f3 = {2,4,0};
ftable success = { (features)f1, (features)f2, (features)f3};
	/* the casts are necessary or one gets warnings, why I don't know */

The zero element is being used here to mark the ends of a feature_vec, analogous
to the zero element at the end of a string.

Sam Haradhvala, my coworker here, said that in his application the
ftable success was automaticly generated  and that the set of all f1,
f2, f3... overflowed one of the many target machine linkers.  In such
cases one can do:
feature_vec f1 = {1,2,2,0,
		 ,2,3,0,
		 ,2,4,0};
ftable success = { (features)&f1[0], (features)&f1[4], (features)&f1[7]};

rpw3@fortune.UUCP (02/07/84)

#R:houxt:-35400:fortune:16200019:000:1050
fortune!rpw3    Feb  7 00:27:00 1984

Gee, we used to optimize loops like that with a 'DBcc', until the first time
somebody tried to do more than 65536 things and discovered what the compiler
person should have discovered before he ever hacked it in (it's o.k., he fixed
it before we shipped it), namely:

	[From the 68000 User's Manual, Third Edition, page 115]
	"...If the termination condition is not true, the low-order
	16 bits of the data counter are decremented by one..."

Copying more than 256K bytes (65k longs) is not that uncommon
these days.  (How much memory does your system have?)

If a "move word" was used to set up the counter (optimize! optimize!),
you also get VERY strange results if the counter value gets used
for anything inside the loop, regardless of the size of the count.
Even with "move long", guess what prints about halfway through this:

	for( i = -10, i < 10, i++) printf("%d\n", i);

Rob Warnock

UUCP:	{sri-unix,amd70,hpda,harpo,ihnp4,allegra}!fortune!rpw3
DDD:	(415)595-8444
USPS:	Fortune Systems Corp, 101 Twin Dolphins Drive, Redwood City, CA 94065

barrett@hp-dcde.UUCP (02/21/84)

What does that response have to do with net.lang.c?

johnl@haddock.UUCP (03/15/84)

#R:smu:13800001:haddock:12400004:177600:480
haddock!johnl    Feb 13 15:18:00 1984

In regard to this:

	cat = foo ? fu = bar : mouse;

Precedence has nothing to do with it.  Precedence only matters when there
are two possible legal parses, such as "a + b * c" which could be either
"(a + b) * c" or "a + (b * c)" without precedence to disambiguate.

The only possible parse for the first expression is:

	cat = foo ? (fu = bar) : mouse;

so that the "fu = bar" assignment happens before the assignment to cat
if it happens at all.  Golly.

John Levine, ima!johnl

mnc@hou2g.UUCP (#M.CONDICT) (03/19/84)

> In regard to this:
> 
> 	cat = foo ? fu = bar : mouse;
> 
> Precedence has nothing to do with it.  Precedence only matters when there
> are two possible legal parses, such as "a + b * c" which could be either
> "(a + b) * c" or "a + (b * c)" without precedence to disambiguate.
> 
> The only possible parse for the first expression is:
> 
> 	cat = foo ? (fu = bar) : mouse;
> 
> so that the "fu = bar" assignment happens before the assignment to cat
> if it happens at all.  Golly.

What's wrong with the parse:  (cat = foo) ? (fu = bar) : mouse;  ?
This evaluates an if-then-else expression containing two assignments as
side effects and then throws away the result.

Michael Condict    ...!hou2g!mnc

jc@inmet.UUCP (05/05/84)

#R:nsc:-84400:inmet:5000015:177600:809
inmet!jc    Apr 26 09:41:00 1984

Re: the 2nd-place winner of the Obfuscation contest.

What's this supposed to do?  On our VAX, its output is the following,
where the 2nd and 3rd lines are the hex digits of the chars:

'",x);_/*_\                                                                    
22272302205                                                                    
72C89B9FAAC                                                                    

The other two programs were sorta cute, but this makes no sense.  Aren't
the winners supposed to do something interesting/entertaining?  Maybe we 
got a garbled version of the program, or it doesn't work on a VAX?

					John M Chambers [inmet!jc]
					Intermetrics, Inc.
					735 Concord Ave.
					Cambridge, MA 02138
"I don't have any solution but I certainly admire the problem."

jc@inmet.UUCP (05/05/84)

#R:nsc:-84500:inmet:5000016:177600:1295
inmet!jc    Apr 26 11:38:00 1984

/*(The original form of this program, while technically impressive, 
 * nonetheless  produced  output containing unbalanced parentheses.  
 * We in the software business  have  enough  of  a  reputation  as 
 * illiterate  slobs,  without  this  sort  of  thing  being openly 
 * rewarded!  In an effort to  encourage  programmers  to  generate 
 * software  that  is more English-like and user-friendly, I submit 
 * the following modified version. :-)
 */
/* Portable between VAX11 && PDP11 */

short main[] = {
	277, 04735, -4129, 25, 0, 477, 1019, 0xbef, 0, 12800,
	-113, 21119, 0x52d7, -1006, -7151, 0, 0x4bc, 020004,
	0x3A28, 10541, 2056, 04010, 4548, 3044, -6716, 0x9,
	4407, 6, 5568, 1, -30460, 0, 0x9, 5570, 512, -30419,
	0x7e82, 0760, 6, 0, 4, 02400, 15, 0, 4, 1280, 4, 0,
	4, 0, 0, 0, 0x8, 0, 4, 0, ',', 0, 12, 0, 4, 0, '#',
	0, 020, 0, 4, 0, 30, 0, 026, 0, 0x6176, 120, 25712,
	'p', 072163, 'r', 29303, 29801, 'e'
};
/* 
Original authors:
		Sjoerd Mullender
		Robbert van Renesse
Both @ Vrije Universiteit, Amsterdam, the Netherlands.
	..!decvax!mcvax!vu44!{sjoerd,cogito}
Modified by:
			John M Chambers [inmet!jc]
			Intermetrics, Inc.
			735 Concord Ave.
			Cambridge, MA 02138
P.S. It took me less than 5 minutes to make and test this modification.
Top that, all you hackers!
*/

jc@inmet.UUCP (05/05/84)

#R:yale-comix:-347400:inmet:5000017:177600:343
inmet!jc    Apr 26 15:02:00 1984

<>

I ran this on a PDP-11 using Whitesmiths' C compiler, and got:

19 2
19 3
30 5
30 6

This seems almost correct, except for the truncation that turned the
two 20s into 19s.
					John M Chambers [inmet!jc]
					Intermetrics, Inc.
					735 Concord Ave.
					Cambridge, MA 02138
"I don't have any solution but I certainly admire the problem."

mpackard@uok.UUCP (05/13/84)

#R:smu:13800001:uok:3400002:37777777600:174
uok!mpackard    May 13 13:06:00 1984

Concerning mr perry or ms perry, I never did determine the sex
but it doesn`t matter because (s)he is on the rag!
(s)he`s so smart that (s)he doesn`t have anyone to talk to.

bobm@zinfandel.UUCP (05/16/84)

#R:wivax:-1945700:zinfandel:14600018:177600:755
zinfandel!bobm    May 14 23:18:00 1984

> 019 being equal to 17 decimal is an attribute of the VAX PCC lexer;
> it is not a part of the C language definition.
> 
> Without disregarding the many baroque qualities of the language
> definition, one must realize that 'net.lang.c' is a newsgroup for
> Talmudic dissection of Kernighan and Ritchie--weird questions are
> expected.  ANSI C should help clarify some of the ambiguities.
> God help us when net.lang.ada really begins to be used!  
> -- 
> /Steve Dyer
> decvax!bbncca!sdyer
> sdyer@bbncca
> /* ---------- */

K&R, Appendix A (the REAL reference; pay no attention to what it says
in the chapters), Section 2.4.1, states, "....  The digits 8 and 9 have
octal value 10 and 11 respectively...."

					Scholar of the Holy Law,
					Bob Miller

ajs@hpfcla.UUCP (06/10/84)

> isn't  C++ == D??

Depends on the value of C.

Of course, 'C'++ == 'D', except the operation is illegal.

ado@elsie.UUCP (06/20/84)

>	> isn't  C++ == D??

>	Depends on the value of C.

>	Of course, 'C'++ == 'D', except the operation is illegal.

Actually, ++'C' == 'D', except the operation is illegal.
--
	...decvax!allegra!umcp-cs!elsie!ado	(301) 496-5688
	(the DEC and VAX in decvax are Digital Equipment Corporation trademarks)

benk@inmet.UUCP (12/02/84)

	How do I apply for maembership in the "Stamp Out BASIC Committee"?
	On second thought: how about a "Stamp out FORTRAN Committee"?
	On third  thought: how about a "Stamp out PL/I Committee"?

	Ben Krepp
	(inmet!benk)

benk@inmet.UUCP (12/02/84)

	If I'm not mistaken UTS C supports a 64 bit integer type;
	I believe that it is called a 'long long'.

	Not a bad idea at all.

	-- Ben Krepp
	(inmet!benk)

jans@mako.UUCP (Jan Steinman) (12/04/84)

Ben Krepp (<inmet.1852> benk@inmet.UUCP) says:
>
>	How do I apply for maembership in the "Stamp Out BASIC Committee"?
>	On second thought: how about a "Stamp out FORTRAN Committee"?
>	On third  thought: how about a "Stamp out PL/I Committee"?
>
It's called "ACM/SigAda, and they're also stamping out JOVIAL, CMS-2, and
(deep breath) C.  (Am I in the wrong newsgroup?  Who's driving this bus?)
(Send flames.  Love mail.)
-- 
:::::: Jan Steinman		Box 1000, MS 61-161	(w)503/685-2843 ::::::
:::::: tektronix!tekecs!jans	Wilsonville, OR 97070	(h)503/657-7703 ::::::

Jeff Hanes (VLD/VMB) <jeffh@Brl-Vld.ARPA> (12/05/84)

>	If I'm not mistaken UTS C supports a 64 bit integer type;
>	I believe that it is called a 'long long'.

For that matter, how about a 128-bit floating point type?
We could call it ... hmm, let's see ... how about:

	"double double" [toil and trouble, fire burn and ... ]

(-: Sorry, couldn't resist that one :-).
Thanks, Bill S., for that timely quote.

				-- Jeff Hanes

henry@utzoo.UUCP (Henry Spencer) (12/08/84)

Actually, there is a "long double" type in some of the recent ANSI C
drafts...
-- 
				Henry Spencer @ U of Toronto Zoology
				{allegra,ihnp4,linus,decvax}!utzoo!henry

rpw3@redwood.UUCP (Rob Warnock) (01/15/85)

+---------------
| Nf-ID: #R:ea:5700031:uo-vax1:55600003:37777777600:180
| Nf-From: uo-vax1!bill    Jan  9 19:10:00 1985
| 
| No, many people test ints, chars, etc.  For example if i and j equal
| 0x01 and 0x02 then i &= j gives i = 0, but i &&= j gives i = 1.
| 
| Mark Aitken
| {tektronix, hp-pcd}!uoregon!marka
+---------------

Hmmm... K & R [p.46, p.191, & p.215] certainly doesn't list "&&=" as one of
the legal operators, and the compiler I use (v.7 derived) doesn't hack it.

A local addition, perhaps?


Rob Warnock
Systems Architecture Consultant

UUCP:	{ihnp4,ucbvax!dual}!fortune!redwood!rpw3
DDD:	(415)572-2607
USPS:	510 Trinidad Lane, Foster City, CA  94404

bill@uo-vax1.UUCP (bill) (01/20/85)

No, many people test ints, chars, etc.  For example if i and j equal
0x01 and 0x02 then i &= j gives i = 0, but i &&= j gives i = 1.

Mark Aitken
{tektronix, hp-pcd}!uoregon!marka

davee@hpgrla.UUCP (davee) (01/24/85)

/***** hpgrla:net.lang.c / cmu-cs-k!tim / 12:54 am  Dec 11, 1984*/
Subject: Re:  PCC and typedefs (why it barfs)

The reason, incidentally, that PCC can't handle typedef identifiers properly
is that they are recognized by the lexical analysis, not as identifiers, but
as type keywords (like "int", etc.)  
/***/

It seems to me that in reading the recent ANSI C draft for the language,
they are proposing doing exactly what you describe above. They have an entry
in their YACC source for TYPEDEF instead of INDENTIFIER. This makes the YACC
easier but may not do what people want for scoping.

Refer to the YACC source posted to net.sources.

Dave Ellis / HEWLETT-PACKARD
hpda!hpfcla!hpgrla!davee

draves@harvard.ARPA (Richard Draves) (01/27/85)

> /***** hpgrla:net.lang.c / cmu-cs-k!tim / 12:54 am  Dec 11, 1984*/
> Subject: Re:  PCC and typedefs (why it barfs)
> 
> The reason, incidentally, that PCC can't handle typedef identifiers properly
> is that they are recognized by the lexical analysis, not as identifiers, but
> as type keywords (like "int", etc.)  
> /***/
> 
> It seems to me that in reading the recent ANSI C draft for the language,
> they are proposing doing exactly what you describe above. They have an entry
> in their YACC source for TYPEDEF instead of INDENTIFIER. This makes the YACC
> easier but may not do what people want for scoping.
> 
> Refer to the YACC source posted to net.sources.
> 
> Dave Ellis / HEWLETT-PACKARD
> hpda!hpfcla!hpgrla!davee

Recognizing typedef identifiers in the lexxer does not make it impossible
to scope them properly; the parser should set a flag when it wants to
disable this recognition.  PCC sets this flag in the wrong places.
Incidentally, I have never seen any other way of handling typedefs.

Rich
-- 

	"If I am conceited, it is the conceit of an amazing man
	 who has never found any surpassing himself."

						Al-Mutanabbi

jim@hpfcla.UUCP (jim) (02/15/85)

/***** hpcnoa:net.lang.c / rlgvax!geller /  8:38 am  Jan 24, 1985*/
Subject: Re: c info (2nd request to a larger group)

Without a doubt two of your finest MS-DOS "C" compilers are the
LATTICE "C" compile (2.14 is the latest version) and the Wizard
"C" compiler. I have been using the LATTICE compiler for more
than 1 1/2 years. The documentation and the product are superb.

As for an editor I could recommend no other editor than the
new BRIEF editor from Solution Systems. The authors are on
the net. BRIEF is an incredibly powerful editor that is a delight
to use. It's MACROS programming language lets you do ANYTHING.

Try them both out. I'd also recommend you try dealing with the
Programmer Shop (ad in PC Tech Journal) as they provide you
with gracious and professional service as well as allowing you
to try various products without definite committments.

I hope this is of some help to you or anyone else in need of some
quality development software. I assure you that asside from being
an extremely satisfied and happy developer I'm not associated with
the above mentioned organizations. Have fun.

					David P. Geller
					{seismo}!rlgvax!geller
/* ---------- */

jim@hpfcla.UUCP (jim) (02/15/85)

I will put in a good word for EDIX.  It's really fast on my MSDOS
machine (which does NOT have a graphics card) and has never crashed
in over a year's use.  It also has regular expression searches and
the key bindings make sense (unless, of course, you've had too much
vi to drink).  My biggest gripe is the Emerging Tech folks don't seem
to recognize their market and push the editor where it will do the
most good.  They seem more interested in the office market and I
suspect EDIX is best loved by displaced UNIX hackers who have to use
MSDOS for one reason or another.

dgary@ecsvax.UUCP (D Gary Grady) (02/21/85)

>>	> > IS there a good C cross compiler which will 
>>	> > produce 360-20 source assembly nmemonics?
>>	> Oh, like, wow.  Are there still 360/20s around?

If I remember correctly, IBM withdrew the 360/20 from the market around
1970.  A typical 360/20 had 15K of core memory and a heavily microcoded
half-word (16-bit) processor, making it the rough equivalent of a
severely stripped-down PCjr.  Forget about the maintenance charges (if
maintenance is even available); the cost of power for the 360/20
probably exceeds the cost of a replacement system!  Get a PC-XT.
-- 
D Gary Grady
Duke U Comp Center, Durham, NC  27706
(919) 684-3695
USENET:  {seismo,decvax,ihnp4,akgua,etc.}!mcnc!ecsvax!dgary

preece@ccvaxa.UUCP (02/25/85)

>	> > IS there a good C cross compiler which will 
>	> > produce 360-20 source assembly nmemonics?
>	> 
>	> Oh, like, wow.  Are there still 360/20s around?
>	[followed by derogatory comments about the 360/20 instruction set]

>	I fail to see the purpose in responding to someone's request for
>	information in this manner.  Do you really think that several
>	hundred thousand dollars, or a few million dollars, worth of
>	equipment is going to be thrown away every time someone comes
>	up with something new?  I think the name for this kind of attitude
>	is "snobbery."
-------------------
I don't know what the specifics would be for a 360-20, but for a lot
of machines of even more recent vintage, you reach a point where the
monthly maintenance charges are higher than the cost of a newer, more
powerful machine.

scott preece
gould/csd - urbana
ihnp4!uiucdcs!ccvaxa!preece

rs@mirror.UUCP (05/28/85)

Yeah, "an array==pointer" is at the heart of C, sort of.  It is only
true when "array" is being passed or received as a parameter.  In this
case, the C automatically changes all array names (e.g., foo(arr))
into addresses of the first element (e.g., foo(&arr[0])).

Why?  Well, I think history had something to do with it.  The
first versions of C had no structures or longs.  Everything fit on
the stack.  'You say arrays don't fit?  Well then, let's just state
that "array==pointer,"' I can hear the Wizard of New Jersey say,
as they huddled around their pdp7...  I think that B and BCPL (father
and grandfather of C*) didn't really support arrays, just pointers
and memory locations.

mike@hpdcdb.UUCP (mike) (06/27/85)

The chief reason pcc compilers cannot make intelligent register variable
selection automatically is that they are single-pass compilers. Some kind
of usage count is necessary to select candidates for register variables.
By the time the compiler can accumulate a usage count, however, a
single-pass compiler has already generated code.

Automatically derived usage counts are invariably counts of static
references.  Such counts are useful but for my money I'd prefer dynamic
usage counts. Consequently I've yet to see a compiler algorithm for
automatic register variable selection that can beat explicit programmer
selection. If anyone does have such an algorithm, please share it.

Given the gutsy nature of C that allows the programmer great freedom
to allocate registers as he sees fit, I would not be surprised at all
if an automatic register allocator was greeted with loud cries of anguish
from the programmer community.

Register variables do alter the behavior of certain programs because
the pcc compiler generates code sequences based on cost estimates. Since
the use of register variables reduces the cost of certain subtrees it
can change the order of evaluation in the generated code. The only
situations I've seen where this matters is in the case of ambiguous
source code constructs such as

	a[i] = a[i++];

I don't have a great deal of sympathy for anyone who gets different
results depending on whether or not "i" is a register variable. K & R
specifically warn about such constructs.

Mike McNelly
Hewlett-Packard Corp.
hplabs!hpfcla!mike

oz@yetti.UUCP (Ozan Yigit) (07/05/85)

In article <504600001@hpdcdb.UUCP> mike@hpdcdb.UUCP (mike) writes:
>The chief reason pcc compilers cannot make intelligent register variable
>selection automatically is that they are single-pass compilers. Some kind
>of usage count is necessary to select candidates for register variables.
>By the time the compiler can accumulate a usage count, however, a
>single-pass compiler has already generated code.

	VMS C compiler is essentially a single pass compiler also,
	(It performs the second pass if the program contains any case
	statements) yet, it is a well known REGISTER HOG !!! It will
	use every register, including AP, when it is available.. 
>
>usage counts. Consequently I've yet to see a compiler algorithm for
>automatic register variable selection that can beat explicit programmer
>selection. If anyone does have such an algorithm, please share it.
>
	Check out the DEC book on their PL/1 and C compilers. (I cannot
	remember the full title..)
>
>Given the gutsy nature of C that allows the programmer great freedom
>to allocate registers as he sees fit, I would not be surprised at all
>if an automatic register allocator was greeted with loud cries of anguish
>from the programmer community.
>
	I think the opinion is divided on that. Especially on RISC
	architectures, programmer could stifle the compiler from
	generating better code by not properly declaring the
	variables (assuming that the compiler is good old pcc,
	and does not use registers unless told). 
	On the other hand, compiler should definately accept "advise" 
	from the programmer, since henry@utzoo is so fond of reminding, 
	compilers (and program beautifiers..) cannot read minds. 
	Cornell tried to read minds at one time with their PL/C 
	compiler. It did not work too well.

>Register variables do alter the behavior of certain programs because
>the pcc compiler generates code sequences based on cost estimates. Since
>the use of register variables reduces the cost of certain subtrees it
>can change the order of evaluation in the generated code. 

	Is this an argument *for* or *against* the register variables ??
	There is no question that certain optimization techniques may
	alter the order of evaluation by means of loop unrolling[1], or
	code motion out of loops[1], but under *no* circumstances
	should this provide a different result. Otherwise, compiler
	should be considered *broken*. 

>Mike McNelly

	[1] Bentley, Jon Luis, "Writing Efficient Programs",
	    Prentice-Hall, 1982
-- 

Oz	[all wizardesque side effects are totaly unintentional,
	unless stated otherwise..]

	Usenet: [decvax | allegra | linus | ihnp4] !utzoo!yetti!oz
	Bitnet: oz@ [yuleo | yuyetti]
-------------
Support GNU. Consider the 3-muskateers' motto:
	ONE FOR ALL - ALL FOR ONE

guy@sun.UUCP (07/08/85)

> AT&T compilers these days all come with a tool, call "dis", for
> disassembler. that look at object files and tell you exactly what
> instructions are in them.

Well, some AT&T compilers, anyway - the S5R2 documentation describes DIS(1)
as "3B20 only".

> This is neccessary because it is sometimes not possible to look at a
> .s and tell exactly what instructions the assembler will produce. For
> example an assembler might replace some long forms of jumps by short
> forms.

The PDP-11, VAX, and 68000 assemblers I've seen don't replace long jumps
with short jumps; they replace a "generic" jump with a short or long jump.
Then again, for the purposes of inspecting generated code to see "how good
it is", this shouldn't make much of a difference; looking at the ".s" files
should suffice.  The disassembler may be useful for 3Bs; I believe they have
a "generic" assembler language which translates into 3B20 or WE32000-series
binary code.

	Guy Harris

faustus@ucbcad.UUCP (07/13/85)

> Let's say I am a person whose programming experience consisted a few
> high school and college courses in Basic & Pascal.  Ok, now let's say I
> have a problem that I want solved by a programmer.  The programmer comes
> back to me with a program which doesn't do quite what I wanted.  Now
> from the comments it looks like the program should work right.  The
> problem is in the code.  Now the programmer goes off and tries to fix
> it, thinking he knows exactly what I want.  But when he comes back with
> the revised program, it still doesn't do what I wanted.  Now the
> comments were not enough to understand why the program doesn't do what I
> wanted.  Therefore I must look at the code ("Foul", I hear you say.
> "What are you doing looking at his code; you're not an experienced C
> programmer!"  Well who else can look at it, if the programmer can't fix
> it himself?  At least I know what I want done).  The program turns out
> to be a full of these strange little idioms, which I've never seen
> before.  Luckily, some of the code is readable, so I hope that what is
> wrong is in that.  Let's say the problem with the program is that a
> variable is being incremented when it shouldn't be.  However I don't
> know that the variable is being incremented because I see this cryptic
> "stuff++" which I pretty much ignore because the code is full of things
> like that which gets lost in the shuffle.  I'm lost, the programmer
> doesn't know what's wrong, and we're stuck.
> 
> However if the program said "stuff = stuff + 1" or even
> "increment(stuff)", I could say "Aha! I think I know why it's not
> working. That variable 'stuff', why is it being incremented.  I don't
> think it should be incremented".  The programmer removes that line, the
> program is fixed, and we all live happily ever after.
> 
> I know this was a rather long story, but I had to get my point across
> somehow.  Remember that the "I" in that story could be someone you will
> be working for.

You should either: (1) Hire programmers who do the right thing, or (2)
Learn C. If there are nice features in a language like "i++", it is
silly to expect programmers not to use them because non-programmers
won't understand them. If you don't understand "i++", you sure won't
understand "p->foo". Besides, many people have pointed out that you
sometimes have to be a bit obscure to get efficient code -- if you write

	while (p->duck)
		p++;

instead of

	while (p++->duck)
		;

you are likely not to get the loop compiled with auto-increment instructions...

Anyway, you should admit that you are fighting a losing battle -- C
programmers write programs that should be understood by and only by other
C programmers, and if you don't know C you have no business trying to
understand it.

	Wayne

ned@SCIRTP.UUCP (07/13/85)

> Progams should be as language-independent as possible.  It shouldn't
> matter whether the program is in C, Pascal, Ada, or even the dreaded
> APL, but that it can be understood by *anyone* who needs to look at the
> program.  If you limit that *anyone* to "experienced C programmers",
> you're limiting the possibilities of that program.
> 
> Dan  /* comments are of course welcome */

I disagree.  If programs were written to be as "language-independent" as
possible, what kind of languages would we be using???  Wouldn't this have
the net effect of significantly slowing the evolution of computer language?

I mainly program in C and Pascal, but I'm very glad that I had the opportunity
to learn and use APL.  It is a unique language with many good ideas.  It is
not perfect, but then no language is.  It is not effective in all applications;
no language that I'm aware of is.  But I found it to be a refreshing, exciting,
and fun(!) way to solve problems.  Best of all, it made me a better programmer.

The short-term benefits of *everyone* programming in compliance with the
current popular semantic model are appealing, but the long-term results
would be to retard the research and development of other forms of human/
computer communication.  In light of the fact that many of today's problems
cannot be adequately expressed to a machine, this would be a grave mistake.

-- Ned Robie

bc@cyb-eng.UUCP (07/13/85)

I am surprised no one has mentioned "The Elements of Programming Style",
by Kernighan and Plauger.  It is an EXCELLENT book; I wish the world would
read (and abide by) it.

-- 

  /  \    Bill Crews
 ( bc )   Cyb Systems, Inc
  \__/    Austin, Texas

[ gatech | ihnp4 | nbires | seismo | ucb-vax ] ! ut-sally ! cyb-eng ! bc

root@bu-cs.UUCP (07/13/85)

I remember teaching that strncpy hack...except it was:

	mvi	str,c' '
	mvc	str+1(length-1),str

hey, if you're gonna make it machine-dependant

	!MAKE IT MACHINE DEPENDANT!

(where's my green card...)

	-Barry Shein, Boston University

lee@eel.UUCP (07/13/85)

	The degree of readability of "if ((foo=..." is a reasonable subject
	of debate, but I decline to back down on the general assertion that
	one mark of a professional is a genuine effort to *maximize*
	readability, not just to bring it above some minimum threshold.

As with any form of communication, there is no absolute scale on which
to evaluate a speech, lecture, article or program as to its "readability",
that is, the degree to which a person can absorb the information contained
within it.  People who teach writing and communication stress that the
item MUST be designed with the expected audience in mind.

An article written to explain FORTRAN to novice programmers will be
inefficient (i.e. not maximally readable) to an experienced programmer.
Likewise, programs "likely" to be read by expert programmers might well be
more readable when "if ((fp=fopen..." is used even if for other programmers
the opposite is true.

Kushall.henr@brl-tgr.UUCP (07/13/85)

DEC is selling the RD50 disk drive kits for Rainbow, Pro350 and DECmate
for $750 as a close the 5 MB drives have beeb dropped. The Rainbow kit
includes Controller, RD50 drive, Power Supply, CPM + MS-DOS operating
systems.

ED

ABN.ISCAMS@brl-tgr.UUCP (07/14/85)

Re getting the command line in CP/M-80:  FACT - in Version 1, at least,
of Turbo Pascal, Turbo eats everything after maybe the 30th or 31st
character - puts a bunch of (consistent) garbage there.  I have extensively
tested this and am sorely tried by this particular bug!

David P Kirschbaum
Toad Hall
AB.ISCAMS@USC-ISID

mike@hpfclq.UUCP (mike) (07/17/85)

Please don't garbage up net.lang.c for requests of "installation packages".
Let's keep this notes group for language issues.

Mike McNelly	hplabs!hpfcla!mike

mer@prism.UUCP (09/11/85)

/* Written 11:50 am  Sep 11, 1985 by rs@mirror.UUCP in prism:net.lang.c */

> We use the Lattice compiler here at Mirror Systems.
> We purchased it through Unipress.
> We have been using it for many months.
> 
> BEWARE:	Floating point has NEVER worked.  We are getting real
> 	ticked off...
> 	Also, the linker blows up on large symbol tables
> 	(seems to be whenever it's necessary to create a temp
> 	file for it); we were told this one would take a
> 	while.  It's been a couple of weeks, already.
> 
/* End of text from prism:net.lang.c */

Ummm, it's been more like *months*.  Also, the latest version of 
the linker doesn't grok uppercase, but the file "OVERLAY.LIB" is hardwired
into the code, so we're using an older version.

richw@ada-uts.UUCP (09/12/85)

I finally found the Lee paper and it's worth reading if you're
serious about this stuff.

It's pretty close to the code most recently posted, with some
nice additions and good background, etc.  My favorite improvement
over the stuff I posted was the macro to declare Exceptions.
It's something like:

#define New_Exception(e)   Exception e = "e";

Duh!  I thought you couldn't do that (i.e. didn't think e would
be replaced since it's in a string), but did I bother to TRY?
Nooo...

-- Rich

richw@ada-uts.UUCP (09/19/85)

I've been told that the ``feature'' allowing one to substitute
a macro argument into a string is actually a common bug
in C compilers which my C implementation suffers from, so
be warned...

-- Rich

marc@hpltca.UUCP (marc) (10/18/85)

Well, I own about 20 books on the topic, and by far and away the best one,
in my opinion, is "Learning to Program in C", by Thomas Plum, published by
Prentice-Hall.  Plum has several more books, published this year, on such
topics as how to write efficient C programs and reliable data structures.
If I were going to do it all again, I'd buy everything Kernighan and Plum
ever wrote and skip everything else.

Marc Clarke, Hewlett-Packard, hplabs!hpfcla!hpltcb!marc

rs@mirror.UUCP (03/27/86)

A friend of mine recently did what you want.  We were running UniPlus
SysV on a 68000.  He was doing image compression and needed to sample
every n'th bit in a source, writing it out as the m'th bit in the
destination.  The 68000 "test bit specified by register X" was too
slow, and he also wanted to unroll the loops.  As I remember, the code
went something like this:

typedef int	(*PFI)();
typedef short	  WORD;
extern char	*malloc();

PFI
generate(count)
    int		 count;
{
    WORD	*base;
    WORD	*p;

    base = p = malloc(sub_size);
    *p++ = prolog;				/* he had the actual	*/
    *p++ = prolog;				/* hex words of the	*/
    while (--count >= 0) {
	*p++ = test_bit;			/* code here, not these	*/
	*p++ = branch_if_zero .+2;		/* "mnemonics"		*/
	*p++ = mv 0,(a0);
	*p++ = skip;
	*p++ = mv 1,(a0);
	*p++ = decrement and branch if non-zero .-5;
    }
    *p++ = epilog;
    *p++ = return;
    return((PFI)base);
}

Then, in the main routine he had something like this:
    PFI *p, generate();
    p =generate(5);
    (*p)();

I may have a cast or two slightly wrong, but the basic principle
is sound.  (Well, it worked, at any rate; I don't know how sound
the basic principle really is :-)

--
Rich $alz	{mit-eddie, ihnp4!inmet, wjh12, cca, datacube}!mirror!rs
Mirror Systems	2067 Massachusetts Avenue  Cambridge, MA, 02140
Telephone:	6,176,610,777

dougm@ico (06/29/86)

/* Written  1:46 pm  Jun 27, 1986 by rbutterworth@watmath.UUCP in ico:net.lang.c */
/* ---------- "Re: #if foo vs #if defined(foo)" ---------- */

> A CPP which silently takes undefined symbols to be 0 can be quite
> dangerous.  Consider the following case with these definitions
...

> "#if squat||(3*y)".

> I think the effort of having to use "#ifdef x" or "#if defined(x)"
> instead of lazily using "#if x" is well worth it.

I have to agree.  Another sloppy practice I've come across is not
using the "&&" and "||" but using "&" and "|" as equivalent to the
doubled form.  Then you end up spending time searching for a problem
when someone changes a
	#define token
to
	#define token 2
and having the 
	#if token&token2
suddenly not work.  Using the defined(token) construct when you only
care about defined or not defined can save more time than the time it
takes to type it in.

Of course, you still have the people who think that
	#ifdef token&token2
does the same thing as
	#if defined(token)&&defined(token2)

karl@haddock (08/11/86)

[In the expression "cond ? voidf() : voidf()",]
>The void values are not thrown away!

True.  They are being passed to the ?: operator.

>Remember that (A?B:C) is an expression *returning a value*.

Yes, it is an expression (as opposed to a statement); however, some
expressions have type "void" (and no value).  This is (or should be)
one of them.

>C is giving the error because it can't determine the type.

No, it's giving the error because the compiler writer overlooked a case.
I'm glad X3J11 has fixed this.

Btw, a case where it could be useful (and where if...else won't do) is
"(cond ? voidf0() : voidf1()), intf2())" used in an integer context.  I
admit I have no plans to use this feature in the near future, but it's a
perfectly reasonable thing to allow.

Karl W. Z. Heuer (ihnp4!ima!haddock!karl), The Walking Lint

karl@haddock (08/12/86)

dg_rtp!throopw (Wayne Throop) writes:
>(As a small nit, I'd druther that the draft standard would allow a void
> expression to be cast to void, but that's a fairly small quibble.)

Void to void is illegal?  Sonofagun, you're right, and they even made it
explicit.  How strange.

Here's another restriction I just encountered: you can't typedef to void.
This is probably because typedef is syntactically a storage class specifier,
so it "looks like" an attempt to declare a void variable.

I was trying to declare "typedef void dead;" so that I could distinguish
between functions that return nothing (void perror(char *), setbuf(FILE *,
char *), nullf(void)) from those that don't return (dead exit(int),
abort(void), longjmp(jmp_buf, int)).  Again, it's a small quibble; I'll
just use #define instead.

Karl W. Z. Heuer (ihnp4!ima!haddock!karl), The Walking Lint

aglew@ccvaxa.UUCP (08/15/86)

>I was trying to declare "typedef void dead;" so that I could distinguish
>between functions that return nothing (void perror(char *), setbuf(FILE *,
>char *), nullf(void)) from those that don't return (dead exit(int),
>abort(void), longjmp(jmp_buf, int)).  Again, it's a small quibble; I'll
>just use #define instead.
>
>Karl W. Z. Heuer (ihnp4!ima!haddock!karl), The Walking Lint

Good point, though - an optimizing compiler could take advantage of
knowledge that a function doesn't return to do better register allocation,
etc. Should this be in the langauge, or is a convention like

    if( error_condition ) {
	exit(1);
	/*NOTREACHED*/
    }

enough? (Rhetorical question: obviously, you should specify it at the point
of declaration of such a function, not at the point of use.)

Andy "Krazy" Glew. Gould CSD-Urbana.    USEnet:  ihnp4!uiucdcs!ccvaxa!aglew
1101 E. University, Urbana, IL 61801    ARPAnet: aglew@gswd-vms

karl@haddock (08/15/86)

mmintl!franka (Frank Adams) writes:
[re the expression e1?e2:e3 where e2 and e3 are void]
>It seems to me that there are two different paradigms for how to interpret
>the ?: operator here.  One is as an ordinary operator, which returns one of
>the values of e2 or e3, depending on the value of e1.  Under this
>interpretation, it does not seem to me appropriate to permit e2 and e3 void,
>since in that case they have no values.
>
>The other paradigm is that e1?e2:e3 is precisely one of e2 or e3 ...  This
>is a very reasonable interpretation; but [then it should preserve lvalues].
>In particular, one could write "e1?e2:e3 = e4;".

I see your point.  I think both voids and lvalues should be allowed, though
the argument for the latter is less obvious.  I've had a few occasions where
I wanted to use a conditional lvalue, and had to settle for an if-else and a
temporary variable (for e4).  "*(e1?&e2:&e3) = e4;" doesn't work if one of
e2 or e3 is a register or a bit-field, and it looks uglier.  (Also, it tends
to compile into "temp = e1 ? &e2 : &e3; *temp = e4;" rather than "temp = e4;
e1 ? e2 = temp : e3 = temp;", at least on the machines I've tested.)

Karl W. Z. Heuer (ihnp4!ima!haddock!karl), The Walking Lint

karl@haddock (08/16/86)

desint!geoff (Geoff Kuenning) writes:
>While all of this discussion is very interesting and is important to
>achieving a precise language definition, let us not forget that there
>is *no* reason to ever write this particular expression.

I already mentioned one: "(e1?e2:e3),e4".  For another, the types might be
unknown, if they are arguments in a macro; in this case I would want the
macro to work on void as well as valued expressions.

>[If-else] is better style anyway;  it makes use of a construct that
>people are much more used to, and it makes it clearer [what you are doing].

I won't argue that; though style is less important when you're writing a
macro.  Btw, I've been hacking at tail.c recently, and noticed that it has
an expression statement of the form "flag ? f1() : f2()", where f1() and
f2() are functions returning no value.  The compiler accepted it, because
they were (implicitly) declared int rather than void.

Karl W. Z. Heuer (ihnp4!ima!haddock!karl), The Walking Lint

karl@haddock (08/20/86)

ccvaxa!aglew (Andy Glew) writes:
>[haddock!karl (Karl Heuer) writes:]
>>I was trying to declare "typedef void dead;" so that I could distinguish
>>between functions that return nothing (void perror(char *), setbuf(FILE *,
>>char *), nullf(void)) from those that don't return (dead exit(int),
>>abort(void), longjmp(jmp_buf, int)).
>
>Good point, though - an optimizing compiler could take advantage of
>knowledge that a function doesn't return to do better register allocation,
>etc. Should this be in the langauge, or is a convention like /*NOTREACHED*/
>enough? (Rhetorical question: obviously, you should specify it at the point
>of declaration of such a function, not at the point of use.)

I posted this question before, and most of the response was on the order of
"this declaration isn't NEEDED".  True.  But "void" wasn't necessary either;
the language lasted quite some time with nonvalued int functions (which are
still quite common, especially since "int" is the default datatype).  The
addition of "void" didn't improve the generated code of any compiler I know
(the function and its caller both knew that no value was being used).  As far
as I can tell, it was added merely to allow clearer code, and to simplify
catching certain kinds of errors.

The same can be said of boolean expressions and dead functions.  The only
reasons for not adding them, as far as I can see, are as follows:

[0] Inertia, of course.

[1] It requires a new keyword (someone suggested that dead functions can be
reuse the keyword "goto", but I don't think it's appropriate).

[2] It won't be usable much.  This is a valid point.  There were a *lot* of
nonvalued int functions before void was invented; there are only a handful of
standard functions that are dead-ends.  Booleans are more common, especially
in programs like "ls" that have a flag for each option.

But I digress.  Returning to your comments: as for optimization, the calling
function can take advantage of the knowledge by omitting extra branches (e.g.
in "if (err) exit(1); else ...") or returns ("exit(0)" at the bottom of
main()).  This improves the space (but not time) efficiency, but not by much.

I presume your comment about register allocation referred to the dead-end
itself, in that the caller's registers need not be saved.  I don't think you
can assume this: the function "dead f() { for (;;) pause(); }" could be
interrupted by a signal, whose handler could longjmp() to f's caller, whose
registers must be recoverable.  For similar reasons, it probably isn't okay
to optimize the function call into a jump, unless you're careful with the
stack.

But I really hate having to write /*NOTREACHED*/ to keep lint happy!

Karl W. Z. Heuer (ihnp4!ima!haddock!karl), The Walking Lint
(Sorry if I've been rambling; it's late, and I should be in bed.)

bright@dataio.UUCP (Walter Bright) (08/22/86)

In article <86900019@haddock> karl@haddock writes:
>ccvaxa!aglew (Andy Glew) writes:
>>[haddock!karl (Karl Heuer) writes:]
>>>I was trying to declare "typedef void dead;" so that I could distinguish
>>>between functions that return nothing (void perror(char *), setbuf(FILE *,
>>>char *), nullf(void)) from those that don't return (dead exit(int),
>>>abort(void), longjmp(jmp_buf, int)).
>>
>>Good point, though - an optimizing compiler could take advantage of
>>knowledge that a function doesn't return to do better register allocation,
>>etc.
>
> The only
>reasons for not adding [dead functions], as far as I can see, are as follows:
>
>[2] It won't be usable much.  This is a valid point.  There were a *lot* of
>nonvalued int functions before void was invented; there are only a handful of
>standard functions that are dead-ends.

	Functions that never return are used a LOT in code that is loaded
	with self-debugging assertion macros:

	    #define assert(e) ((e) || printmsgandexit("e",__LINE__,__FILE__))

>As for optimization, the calling
>function can take advantage of the knowledge by omitting extra branches (e.g.
>in "if (err) exit(1); else ...") or returns ("exit(0)" at the bottom of
>main()).  This improves the space (but not time) efficiency, but not by much.
>
>I presume your comment about register allocation referred to the dead-end
>itself, in that the caller's registers need not be saved.  I don't think you
>can assume this: the function "dead f() { for (;;) pause(); }" could be
>interrupted by a signal, whose handler could longjmp() to f's caller, whose
>registers must be recoverable.  For similar reasons, it probably isn't okay
>to optimize the function call into a jump, unless you're careful with the
>stack.

	A good optimizer can make some important optimizations if it
	knows that a function will never return:

	1) Register contents destroyed by the function call do not affect
	the caller. This has important ramifications when doing register
	allocation by coloring.

	2) Functions are presumed to modify all globals and all indirect
	references. Thus, if the function does not return, the optimizer
	can find more common subexpressions, copy propagations, etc.

karl@haddock (08/22/86)

ttrdc!levy (Dan Levy) writes:
>whatsa matter with "#define biff(pow) { if (pow) kayo(); else oof(); }"?

Since biff is now a complete statement (no trailing semicolon required), you
still can't write "if (...) biff(pow); else ...".  You could leave out the
semicolon, but this requires the user to know that biff is implemented this
way.  This is why the unusual definition "do {...} while (0)" (no trailing
semicolon) has been offered.

Ideally, it's nice for a macro to be an expression, since the function call
it resembles is an expression.  Thus ?: is preferred when possible.  (It is
evidently *not* possible in some compilers yet.)

>Bright (et al) have been saying "change the definition of C to allow this."

It's not clear whether this involves a change in the definition, or just a
bug fix in some existing compilers.

Karl W. Z. Heuer (ihnp4!ima!haddock!karl), The Walking Lint

franka@mmintl.UUCP (Frank Adams) (08/23/86)

In article <86900015@haddock> karl@haddock.UUCP writes:
>... "(e1?e2:e3),e4".

It occurred to me that there is a workaround which deals not only with the
void case, but also with the case where the types of e2 and e3 are different
(and the result is to be ignored): "e1?(e2,0):(e3,0)".  I'm not sure whether
to recommend this in cases where an expression is required instead of a
statement, or to draw back in horror.

>For another, the types might be
>unknown, if they are arguments in a macro; in this case I would want the
>macro to work on void as well as valued expressions.

This case is not covered by my suggestion.  I find it hard to imagine doing
it, however.

Frank Adams                           ihnp4!philabs!pwa-b!mmintl!franka
Multimate International    52 Oakland Ave North    E. Hartford, CT 06108

karl@haddock (09/03/86)

Note: In my earlier posting I came to the tentative conclusion that the "dead
function" concept (a function which never returns, e.g. exit) would probably
not be sufficiently useful to be worth adding a new builtin type.  I haven't
changed my mind; I just want to point out some possibilities.

dataio!bright writes:
>In article <86900019@haddock> karl@haddock writes:
>>[2] It won't be usable much.  This is a valid point.  There were a *lot* of
>>nonvalued int functions before void was invented; there are only a handful
>>of standard functions that are dead-ends.
>
>Functions that never return are used a LOT in code that is loaded
>with self-debugging assertion macros:
>           #define assert(e) ((e) || printmsgandexit("e",__LINE__,__FILE__))

But there are typically a very small number of such functions (usually one)
per application.  (Btw, I wouldn't want to assume that a dead function can be
the right argument of "||".)

>A good optimizer can make some important optimizations [with register usage,
>information about global and indirect references] if it knows that a
>function will never return.

Good point.  I hadn't thought of that type of optimization.

Another "advantage" of an explicit declaration for dead functions is that,
logically, one should be able to cast from "dead" into any other type -- a
feature not available with "void".  Since the code that would implement the
cast is never reached, it need not do anything.  This would allow
	extern double atod();
	extern dead abort();
	x = isfloatstr(s) ? atod(s) : abort();
which is a pretty bad example, so let me try again.

"pointer to dead function" (I can't really call it "pointer to function
returning dead", can I?) could be cast into "pointer to function returning T"
for any type T.  This would allow
	extern T f0(), f1(), f2(), f4();
	extern dead abort();
	T (*)() tab[] = { f0, f1, f2, abort, f4 };

Note that this can ALREADY BE DONE using an implicitly dead function.  The
functions in libc are declared "void" (that being the closest match), but it
is perfectly legal to write
	double bomb(char *s) {
		write(2, s, strlen(s));
		exit(1);
	}
An explicit "dead" declaration, with permission to cast to other types, would
seem to be more sensible.  (Though I think I'd want to require the cast to be
explicit.)

Karl W. Z. Heuer (ima!haddock!karl; karl@haddock.isc.com), The Walking Lint
(The opinions expressed above are not necessarily those of the author.)

karl@haddock (09/05/86)

killer!tad (Tad Marko) writes:
>In my original article, ... I was asking if I should use
>"foo(parm) char **parm; {...}" or "foo(parm) char *parm[]; {...}"
>and I *DID* test both of them, and they both worked.

Okay, that's a more sensible question.  The official truth is that in this
context, they are equivalent.  However, my *personal opinion* is that the
former is "more correct"; the latter is a kludge where the compiler figures
out what you "must have really meant" and converts it for you.  (Kind of like
how some compilers will interpret "&a" as "&a[0]" if "a" is an array, though
in that case you'll probably get a warning at least.)

My recommendation is to write "char **parm"; it causes less confusion.  Even
if you do write "char *parm[]", you are declaring a pointer, not an array.
(Similarly, a formal argument declared "float parm" really declares a double,
which is also quite confusing, e.g. if you take its address.)

Oh yes, some compilers used to consider a parameter declared "type x[]" to be
a *non-modifiable* pointer to type.  That no longer seems to be popular.

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

jsdy@hadron.UUCP (Joseph S. D. Yao) (09/11/86)

In article <1761@mmintl.UUCP> franka@mmintl.UUCP (Frank Adams) writes:
>>For another, the types might be
>>unknown, if they are arguments in a macro; in this case I would want the
>>macro to work on void as well as valued expressions.
>This case is not covered by my suggestion.  I find it hard to imagine doing
>it, however.

When would one try to pass a void "value" to anything, whether or
not it is a macro?  (I agree, that is  v e r y  hard to imagine!)
-- 

	Joe Yao		hadron!jsdy@seismo.{CSS.GOV,ARPA,UUCP}
			jsdy@hadron.COM (not yet domainised)

karl@haddock (09/17/86)

hadron!jsdy (Joe Yao) writes:
>In article <1761@mmintl.UUCP> franka@mmintl.UUCP (Frank Adams) writes:
>>[haddock!karl (Karl Heuer) writes:]
>>>For another, the types might be
>>>unknown, if they are arguments in a macro; in this case I would want the
>>>macro to work on void as well as valued expressions.
>>This case is not covered by my suggestion.  I find it hard to imagine doing
>>it, however.
>When would one try to pass a void "value" to anything, whether or
>not it is a macro?  (I agree, that is  v e r y  hard to imagine!)

Your comment "whether or not it is a macro" suggests that you are assuming
the macro has function semantics, in which case it would not be useful to
hand it a void expression.  But not all macros have this property; consider
    #define new(T) ((T *)malloc(sizeof(T)))
which expects a type rather than an expression.

What I was thinking of (I don't have a specific instance) was a macro whose
return value has the same type as its arguments -- like generic MIN and MAX.
To concoct something that would accept void arguments, you could write
    #define foo(e1,e2) (SOMETHING ? (SOMETHING,(e1)) : (SOMETHING,(e2)))
I suppose.  Of course, the user must be aware that this is a macro, and that
its value is void when its arguments are.  In any case, I agree that it's
not all that likely, but it's not inconceivable.

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