joecar@pyuxe.UUCP (04/02/87)
I'm looking for some information, experiences, opinions, references, etc., that will help me understand the following question: If one writes portable C, does it have to be less efficient than non-portable C ? In other words, does writing portable code add to the run time overhead? Conversely, can I write non-portable code that is more efficient than the portable counterpart? My project is looking at the "cost of portability", and would appreciate any information (or journal references, etc.) that reference any studies on the efficiency of portable C code. Thanks in advance. Joe Carfagno ...!bellcore!pyuxe!joecar
ron@brl-sem.UUCP (04/02/87)
In article <213@pyuxe.UUCP>, joecar@pyuxe.UUCP writes: > > I'm looking for some information, experiences, opinions, > references, etc., that will help me understand the following > question: > > If one writes portable C, does it have to be less efficient > than non-portable C ? > One may right perfectly efficient portable code....most nonportable code is just sloppy rather than machine dependant. Consider the following common errors: 1. Assuming that there is "0" at location "0". 2. Assuming int/char * are the same size. This manifests itself in two ways. First, sometimes people overload the same memory location with both pointers and ints. This is what unions are for. Unions should not be any less efficient than not having them (except where the compiler does initiallization wrong). The second is passing things to subroutines without casting. The assignment operater is pretty forgiving...it knows what the types on both sides need be. Subroutines aren't nearly so clairvoyant, one needs to settle on what the argument type is and force any calls to be made to that type. On machines where it doesn't matter, the cast is a no-op, on others it is essential. 3. Saying int when you mean long... Of course there is no way to determine this really portably, but you can make a small machine header file that sets up typedefs appropriately. The above, when done correctly should have no effect on efficiency (except that it will cause the code to work on machines where it wouldn't before). Now there are a few additional things that require some thinking to do efficiently: 4. Assuming byte ordering in larger objects. There are some real quick get arounds if you "know" your machine's byte order, but this may be wrong on other machines. But this still can be accomodated. For example the 4.2 network code has a macro that converts to network byte order which again is essential for machines with the other order, but is a no-op on the ones where the byte order is the same. 5. Making assumptions about the location of items and padding within structures. This one requires some thought. -Ron
jbuck@epimass.UUCP (04/02/87)
In article <213@pyuxe.UUCP> joecar@pyuxe.UUCP asks: > If one writes portable C, does it have to be less efficient > than non-portable C ? 98.44% of the time, there is absolutely no penalty for writing portable code. For example, casting pointers to the right type, and using "sizeof" rather than putting numbers in the code, and making sure to use "long" instead of int when a value may exceed the range of a 16 bit integer, generates essentially the same code as doing it sloppy does. And it's less likely to be buggy. This is because casts that don't do anything on a particular architecture generate no code, and expressions involving sizeof are evaluated at compile time. SysV vs BSD differences can be taken care of with #ifdefs where they arise. Again, no time penalty. Having said all this, I will make a confession. I wrote a rather large and complex simulator/symbolic debugger for a DSP board designed here at Entropic. It runs on at least 5 different versions of Unix (and one alleged Unix: Eunice) including one with 16 bit ints and 32 bit pointers (thank you, lint!). The only problem encountered in porting was that I had assumed sprintf returns a pointer to the data (as in bsd) while it returns the string length on Sys V. But it makes one glaring nonportable assumption: that the machine it's running on is two's complement. This is because it's simulating a machine that does two's complement math; the alternative would be to make the code run much slower. So yes, there are cases where truly portable code would give an efficiency penalty. But they are rare. Actually, it turns out that casting from unsigned to signed ints and back is guaranteed to simulate two's complement behavior even on non-two's complement machines (see K&R). Had I known this, I could have done the simulator portably without a time penalty. But I don't think I'll go back and change it now. -- - Joe Buck {hplabs,ihnp4,sun,ames}!oliveb!epimass!jbuck seismo!epiwrl!epimass!jbuck {pesnta,tymix,apple}!epimass!jbuck
jtr485@umich.UUCP (04/04/87)
In article <710@brl-sem.ARPA>, ron@brl-sem.UUCP writes: > One may right perfectly efficient portable code....most nonportable > code is just sloppy rather than machine dependant. Consider the following > common errors: > > 1. Assuming that there is "0" at location "0". > 2. Assuming sizeof(int) == sizeof(char *) > passing things to subroutines without > casting. The assignment operater is pretty forgiving...it > knows what the types on both sides need be. Assignment had better be forgiving since type casts are defined in terms of it. > 3. Saying int when you mean long... > Of course there is no way to determine this really portably, > but you can make a small machine header file that sets up > typedefs appropriately. short, int, long is the dumbest part of C. The language should have said there will be a class of types int<ext> where <ext> is the number of bits. But not have specified how many of these there are or what <ext> values they should have. just poor planning. take your header file ONE step further add macros like #define int %$@very bad boy using INT#$ #define long %$@very bad boy using LONG#$ so you CANNOT use int, long etc. > 4. Making assumptions about byte order. > 5. Making assumptions about the location of items and padding within structs. how about: 6. Passing of variable parameter lists. What? You mean it can't be done portably? Oh well, never mind. > -Ron --j.a.tainter
hrubin@osupyr.UUCP (04/04/87)
I frequently find that reasonably good code can be portable, but rarely do I find efficient code portable. In fact, rarely do I find C code (or any other HLL) to be efficient. Assuming that the compiler allows you to put all the variables (but not, of course, the arrays)in registers, the following fragment of code is better on VAXen t = *(m++) ^ *(h++); *(k++) = t; *(z++) ^= t; than t = m[x] ^ h[x]; k[x] = t; z[x] ^= t; x++; while on the pyramid the reverse is true. This is because of the computer architecture. When operations not supported by C are needed, clearly the problem is worse. -- Herman Rubin Until mid May: Department of Statistics, Cockins Hall, 1958 Neil Avenue Ohio State University, Columbus OH43210 hrubin@osupyr or cbosgd!osu-eddie!osupyr!hrubin or ts0474@ohstvma.bitnet "Permanent": Department of Statistics, Purdue University, West Lafayette IN47907 hrubin@l.cc.purdue.edu or ihnp4!pur-ee!stat-l!hrubin or hrubin@purccvm.bitnet
chris@mimsy.UUCP (04/07/87)
[This is long, but if you skip all the rest, please read the last paragraph.] In article <170@osupyr.UUCP> hrubin@osupyr.UUCP (Herman Rubin) writes: >I frequently find that reasonably good code can be portable, but rarely do I >find efficient code portable. By which, I guess, you mean that it takes different `tricks' on different machines to make code efficient, not that because the code has been tweaked for efficiency on one machine, it no longer runs at all on others. >In fact, rarely do I find C code (or any other HLL) to be efficient. I think you will have to define `efficient' first. >Assuming that the compiler allows you to put all the variables (but >not, of course, the arrays) in registers, the following fragment of >code is better on VAXen [reproduced below in expanded form] >while on the pyramid the reverse is true. Really? Let us see. First, here is the code being tested. You did not specify whether the arrays were to be on the stack or whether they were to be static (or, equivalently, global), so I tried it both ways. % cat xx.c /* variants: STACK => stack arrays (else STATIC => static): meaningful iff SUB SUB => subscript code (else ptr) */ f() { register int t; #ifdef SUB register int x; #ifdef STACK int m[4], h[4], k[4], z[4]; #else #ifndef STATIC oops! #else static int m[4], h[4], k[4], z[4]; #endif /* STATIC */ #endif /* STACK */ #else /* not SUB, so PTR */ register int *m, *h, *k, *z; #endif /* SUB */ #ifdef SUB t = m[x] ^ h[x]; k[x] = t; z[x] ^= t; x++; #else t = *m++ ^ *h++; *k++ = t; *z++ ^= t; #endif } And a Makefile to convert this to three assembly variants: C2ASM= cc -O -S all: v0.s v1.s v2.s v0.s: xx.c ${C2ASM} -DSTACK -DSUB xx.c; mv xx.s $@ v1.s: xx.c ${C2ASM} -DSTATIC -DSUB xx.c; mv xx.s $@ v2.s: xx.c ${C2ASM} -DPTR xx.c; mv xx.s $@ Now compare all three. In reverse order: /* Vax: PTR */ xorl3 (r9)+,(r10)+,r0 movl r0,r11 movl r11,(r8)+ xorl2 r11,(r7)+ Not bad. /* Pyr: PTR */ movw (lr1),lr0 xorw (lr2),lr0 addw $4,lr2 addw $4,lr1 movw lr0,(lr3) addw $4,lr3 movw (lr4),tr0 xorw lr0,tr0 movw tr0,(lr4) addw $4,lr4 Well, not so great. All those ++es expand to one instruction each. Next: /* Vax: STATIC SUB */ xorl3 L16[r10],L17[r10],r0 movl r0,r11 movl r11,L18[r10] xorl2 r11,L19[r10] incl r10 Not so bad either. In fact, this takes only one more instruction, and longer addressing modes. /* Pyr: STATIC SUB */ movw L13[lr1 * 4] ,lr0 xorw L14[lr1 * 4] ,lr0 movw lr0,L15[lr1 * 4] movw L16[lr1 * 4] ,tr0 xorw lr0,tr0 movw tr0,L16[lr1 * 4] addw $1,lr1 This is clearly better than Pyr: PTR. (The `* 4' is an addressing mode; these are indeed single instructions.) Finally: /* Vax: STACK SUB */ xorl3 -16(fp)[r10],-32(fp)[r10],r0 movl r0,r11 movl r11,-48(fp)[r10] xorl2 r11,-64(fp)[r10] incl r10 Still not so bad. A bit slower than STATIC SUB, since -offset(fp)'s must be computed each time, but offsets of -64..63 all fit in the instruction itself on a Vax. /* Pyr: STACK SUB */ mova -16(cfp),lr0 movw (lr0)[lr1 * 4] ,lr0 mova -32(cfp),tr0 xorw (tr0)[lr1 * 4] ,lr0 mova -48(cfp),tr0 movw lr0,(tr0)[lr1 * 4] mova -64(cfp),tr0 movw (tr0)[lr1 * 4] ,tr1 xorw lr0,tr1 movw tr1,(tr0)[lr1 * 4] addw $1,lr1 I do not know whether the offsets fit, but this is basically like the PTR version, although I count 11 instructions, and PTR was 10. What have we really learned? Very little. Unless this is an inner loop of an inner loop, none of these variations will make much difference. And if it *is* an inner loop of an inner loop, maybe we should use yet another variant: register int *h = h_arr, *m = m_arr, *k = k_arr, *z = z_arr; register int t, x; ... t = m[x] ^ h[x]; k[x] = t; z[x] ^= t; x++; which, on the Vax, becomes xorl3 (r9)[r6],(r11)[r6],r0 movl r0,r7 movl r7,(r10)[r6] xorl2 r7,(r8)[r6] incl r6 which should be ever so slightly faster than the static version. The `extra' incl in this loop over the pointer version may actually cost less than you think: With a loop around the outside, counting to (say) 1000, we get clrl r6 L2000001: xorl3 (r9)[r6],(r11)[r6],r7 movl r7,(r10)[r6] xorl2 r7,(r8)[r6] aoblss $1000,r6,L2000001 The add, test, and branch instruction makes this *better* than the pointer variant, which requires two separate instructions to do the loop! (It is conceivable that the address computation in this loop, being more complex than in the pointer loop, makes this version slower than the other, but I doubt it---and if you really care, go measure it yourself! :-) ) On the Pyramid, it compiles to this: movw (lr2)[lr5 * 4] ,lr4 xorw (lr0)[lr5 * 4] ,lr4 movw lr4,(lr1)[lr5 * 4] movw (lr3)[lr5 * 4] ,tr0 xorw lr4,tr0 movw tr0,(lr3)[lr5 * 4] addw $1,lr5 which is most likely slightly faster than the static version, and is clearly faster than the other versions. But (and this is an important `but') unless you *know* your program spends a great deal of its time in this loop, there is little point in attempting to optimise it in source code. That such optimisations may be machine dependent is immaterial when said optimisations are unnecessary, and where they *do* make a difference, if you expect the code to be ported, *point them out*! -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7690) UUCP: seismo!mimsy!chris ARPA/CSNet: chris@mimsy.umd.edu
doug@edge.UUCP (04/11/87)
> If one writes portable C, does it have to be less efficient > than non-portable C ? > > My project is looking at the "cost of portability"... I can think of few cases where you can write non-portable but more-efficient C code. Generally you will find that if you write efficient code, the code will be portable /but the efficiency will not/. In other words, you can tune your code to the particular compiler and machine you're running on, and although that code /will/ run on another machine, it won't be fast. The standard areas here are: Register variables, of course. Subscripting versus pointers ( a[i++] versus *pa++ ). Pre/post increment/decrement, especially in subscripts ( a[i]=0; a[i+1]=0; i+=2; versus a[i++]=0; a[i++]=0;). Size of integers ( on a 68000 system, integers are usually 32-bit, but if you multiply them you'll want 16-bit ints ). On some machines, "char"s are slow to access and "short"s would be better; vice versa on other machines. "Unrolling" loops may be advantageous on one machine, but will defeat the instruction cache on another. Now for a more general thought. Hope this doesn't start a flame war. If you are more concerned about efficiency than about portability, then consider this: There are 4 basic reasons for writing a particular program in C instead of in assembler: a) If efficiency is of little consequence -- the program is only going to be run once or twice; b) If portability is important; c) If the programmer is ignorant of assembler; or d) If the boss wants "BIC lighter" programmers: cheap, disposable, and easily replaceable. Thus (from the point of view of an outsider) if you're willing to scrap portability in return for efficiency, you should be programming in assembler instead of C. From the point of view of the programmer, reason (c) might be an overriding consideration. From the point of view of the management, reason (d) might be an overriding consideration. -- Doug Pardee -- Edge Computer Corp. -- Scottsdale, Arizona
bzs@bu-cs.UUCP (04/12/87)
I believe "portability" will become the "goto-less" programming of the 80's. In both cases the suggestions should be applied 98% of the time. The use of goto programming before "the movement" was rampant and causing all sorts of difficulty. I experienced that, I worked with large Fortran programs in which GOTO was the favorite control construct, necessary or not and usually badly thought out (like jumping out and back into the same code segment so the new code can be put at the bottom, no joke.) It was argued that some of this Fortran code was getting all the useful work done in the interstices of the gotos :-) Then came the prosletytes, for example the professors who gave an F on any programming assignment that contained a goto, no matter what the reason (I've personally known professors here with that policy only a few years ago.) Of course that was nonesense. We finally (at least those of us getting work done) came to some agreement that goto's were ok under certain conditions (eg. jumping out of a multiply nested loop on an error condition to quickly "give up", rather than adding noisy bells and whistles flags.) I assume we are somewhere in the same cycle with portability, with the same healthy result. As with gotos, we want to think *real* hard before introducing non-portability into a program. For example, if you can get significant performance increase (which you can demonstrate you can benefit from) and even conditionalize the code so it decides whether to compile portably or not, then go to it. And know the consequences. That's all. Common sense. 98% of the non-portable code smashed (hopefully) just like 98% of the gotos. We all win. -Barry Shein, Boston University
terryk@encore.UUCP (Terence Kelleher) (04/13/87)
Why use C for efficient code? I write controller applications for I/O systems and would rarely consider assembly, even though efficiency is a prime concern. Most C compilers will generate code ,from good source that is as good as the average assembly code. The C code has a better chance of being maintainable, by the author or others. C code can be generated in a fraction of the time that it would take to write the same functions in assembly. I don't think these points are at all original. I have worked on disk systems, communications processors and graphics. In these areas, C has seemed to be the language of choice, even though the nature of low level I/O precludes portability. I summery, C is faster, cheaper and far less hassle than assembly. Even if you don't care about portability, C makes sense. Terry Kelleher Encore Computer Corp.
john@frog.UUCP (04/14/87)
> If you are more concerned about efficiency than about portability, then > consider this: There are 4 basic reasons for writing a particular program > in C instead of in assembler: > a) If efficiency is of little consequence -- the program is only going to > be run once or twice; > b) If portability is important; > c) If the programmer is ignorant of assembler; or > d) If the boss wants "BIC lighter" programmers: cheap, disposable, and > easily replaceable. You forgot e) Reducing the opportunity for bugs by roughly a factor of 10. Most estimates of the average number of bugs in a program indicate that the number is roughly a constant fraction of the number of lines (which I believe is typically 10%), independant of language. A program written in C will typically be 1/10 the size of an equivalent assembly program (depending on the complexity of the C statements), so there are (roughly) 1/10 as many thoughts to mis-think -- in assembly, they may go wrong on a less grand scale, but they still are bugs. I believe there was an article in the most recent Comm. ACM about this general topic. My favorite quote, which didn't arise from this consideration, but does have the same philosophical bent: "Presumably it was essential to get the wrong answer as fast as possible." Kernighan & Plauger, The Elements of Programming Style. -- John Woods, Charles River Data Systems, Framingham MA, (617) 626-1101 ...!decvax!frog!john, ...!mit-eddie!jfw, jfw%mit-ccc@MIT-XX.ARPA "Happiness is the planet Earth in your rear-view mirror." - Sam Hurt, in "Eyebeam, Therefore I Am"
henry@utzoo.UUCP (Henry Spencer) (04/16/87)
> If one writes portable C, does it have to be less efficient > than non-portable C ? It depends on what kind of "non-portable C" you are thinking about. C does let you get moderately intimate with the machine if you really want to. On the pdp11, with a compiler that didn't do global optimization, it was possible for someone familiar with the machine to write C in such a way as to control the exact sequence of instructions. (This is the whole reason for the ++ and -- operators, for example, since they allow fairly direct control of the pdp11 autoincrement/decrement addressing modes.) Code that has been done this way for the sake of absolute maximum speed is inherently fairly machine-specific. ON THE OTHER HAND, if the code avoids making stupid assumptions, it WILL work on other machines, although a lot of the efficiency tailoring may be wasted. Such code is usually hard to read, but its meaning is often machine-independent even though the idioms used to express it are not. In the absence of very good compilers, C written without such machine- specific tweaking will be less efficient than C written with it. HOWEVER. If you are not concerned with squeezing every last microsecond out of the code in arcane ways, and are willing to content yourself with the standard of efficiency set by typical C compilers (not superb, but good compared to a lot of other high-level languages and their compilers), the situation changes. Then there is generally little or no penalty for writing portable code, assuming you know what you're doing. Since only a minute fraction of all C code is sufficiently crucial to justify machine-specific code greasing, the best general statement is that well-written portable C is not significantly less efficient than unportable C. This is true even without considering how "efficient" the code is when it won't run on your new faster machine. -- "We must choose: the stars or Henry Spencer @ U of Toronto Zoology the dust. Which shall it be?" {allegra,ihnp4,decvax,pyramid}!utzoo!henry
doug@edge.UUCP (04/17/87)
I was afraid of this. I figured I'd get some flak when I wrote: me > If you are more concerned about efficiency than about portability, then me > consider this: There are 4 basic reasons for writing a particular program me > in C instead of in assembler: me > a) If efficiency is of little consequence -- the program is only going to me > be run once or twice; me > b) If portability is important; me > c) If the programmer is ignorant of assembler; or me > d) If the boss wants "BIC lighter" programmers: cheap, disposable, and me > easily replaceable. Comment 1: > You left off reason (e), I hope, and that is "If you want Readability and > therefore Maintainability". A C program is no more readable to a C programmer than an assembler program is to an assembler programmer. Ditto for maintainability. The issues of Readability and Maintainability come back to points (c) and (d) above; in other words, whether we're talking about C programmers or assembler programmers. The notorious lack of "commenting" by supposedly professional C programmers really compounds this problem. Professional assembler programmers make dang sure their code is well commented, and the comments are maintained as the program is maintained. This is not a black mark against the C language itself, but rather against the smug arrogance of the scads of C programmers who believe that C is so inherently readable and maintainable that comments are superfluous. Comment 2: > You forgot > > e) Reducing the opportunity for bugs by roughly a factor of 10. I'd like to see some studies on this. I'd believe it for languages like FORTRAN, COBOL, and Ada which prevent the programmer from making really stupid mistakes like not being able to tell a string literal from an array of characters, or arithmetic overflow/divide-by-zero/floating point overflow/underflow, or the infamous "if (x=y)" type of stuff that C allows. C is basically a PDP-11 assembler in a fancy suit, and brings with it all of the screw-up possibilities that you get in real assembler. C is often used in applications where it is a poor fit, and this causes lots of room for screw-ups as the programmer tries to work around the limitations of the language. Device drivers in particular. (Isn't "portable device driver" almost an oxymoron?). All languages, including assembler, are often used in applications where they are a poor fit, with the result that the code tends to be excessively buggy. C zealots usually deny that there exist any applications for which C is a poor fit. Furthermore, C is more difficult to debug than assembler, because (like all other high-level languages) it is distanced from the machine. To debug C you either need to know assembler, and to debug it at the assembler level, or you need a symbolic debugger. A lot of systems don't *have* symbolic debuggers, or the ones they have are not full-functioned. And I haven't seen one yet that will allow a C programmer to make a patch to the code *in C*. And finally, <<<Break out the fireproof suits!>>> all of the above was based on "programmers of equal competency". But consider that point (d) above virtually guarantees that the ever-increasing pool of marginally competent programmers (you know the ones, "I got me a PeeCee and learnt meself how to program in Basic and C") will be hired by penny-pinching companies to program in C. I'm not saying that you personally (whoever you may be) are marginally competent. I *am* saying that if you restrict yourself to the C programming job market, you will be competing with a lot of bozos who are willing to work for peanuts (hey, it beats flipping burgers for a living!). And in return for this limited pay, you will get to maintain the programs those bozos wrote. If you don't like it, the boss can dump you and hire another bozo; he's got 2 dozen resumes on file. *That's* what I mean about BIC lighter programmers. -- Doug Pardee -- Edge Computer Corp. -- Scottsdale, Arizona
al@gtx.com (0732) (04/17/87)
doug@edge.UUCP (Doug Pardee) writes: > consider this: There are 4 basic reasons for writing a particular program > in C instead of in assembler: > a) If efficiency is of little consequence -- the program is only going tome > be run once or twice; > b) If portability is important; > c) If the programmer is ignorant of assembler; or > d) If the boss wants "BIC lighter" programmers: cheap, disposable, and > easily replaceable. One important reason not mentioned above is development time. Unless there are unusual efficiency considerations, The C programmer can program rings around the assembly language programmer because there are fewer low-level discriminations to be made. A well-known folk theorem of computer science says that it takes about as long to write and debug one line of, say, Fortran or C as one line of assembly language. Since the assembly language program is considerably longer, it takes longer to write. > A C program is no more readable to a C programmer than an assembler program > is to an assembler programmer. Ditto for maintainability. The issues of > Readability and Maintainability come back to points (c) and (d) above; in > other words, whether we're talking about C programmers or assembler > programmers. "Higher-level" languages such as C and Fortran were all designed and implemented by exceptionally competent ASSEMBLY LANGUAGE PROGRAMMERS disgusted by the unreadability and unmaintainability of assembly language. Portability was always a secondary issue. > And finally, <<<Break out the fireproof suits!>>> all of the above was > based on "programmers of equal competency". But consider that point (d) > above virtually guarantees that the ever-increasing pool of marginally > competent programmers (you know the ones, "I got me a PeeCee and learnt > meself how to program in Basic and C") will be hired by penny-pinching > companies to program in C. At least the kid with the PC is educable. Spare me from the hardware retread who *knows* that all there is to programming is learning the op-codes for the processor. -------------------------------------------------------------- | Alan Filipski, GTX Corporation, Phoenix, Arizona 85283, USA | | ihnp4!arizona!sunburn!gtx!al -------------------------------------------------------------- God took seven days to create the world; an APL programmer could do it in one line.
henry@utzoo.UUCP (Henry Spencer) (04/19/87)
> ...(This is the whole > reason for the ++ and -- operators, for example, since they allow fairly > direct control of the pdp11 autoincrement/decrement addressing modes.) Oops. This seemed so obviously true, given the close match between the language and the hardware, and the compiler's willingness to do the right thing, that I never checked for sure. Turns out I was wrong: ++ and -- existed in B, well before the 11 entered the picture. They did reflect some influence from the pdp7 hardware, according to Dennis, but the B implementation didn't do anything terribly clever with them. Modify "This is the whole reason" to "This was the most important use"; I think I can defend that one... -- "We must choose: the stars or Henry Spencer @ U of Toronto Zoology the dust. Which shall it be?" {allegra,ihnp4,decvax,pyramid}!utzoo!henry
amos@instable.UUCP (Amos Shapir) (04/19/87)
Most of the arguments on this group stem from the fact that C became too good for its own good. C started as not much more than a structured-programming assembly macros (something like the 800-line 'foogol' compiler posted to net.sources not long ago). It was meant to be a quick & dirty front end to assembly. Then it was discovered that most of the dirty tricks had parallels on other architectures, and C became portable. K&R did a magnificent job of describing what is supposed to be portable, and what is left quick & dirty. However, since C was not meant to be initially portable, many of the checks and guards of high level languages were left out. That made it a nice language to program in. Which made it widely distributed. Which caused much portable code to be written in it - exactly the type of programming HLL's checks and guards were invented for... -- Amos Shapir National Semiconductor (Israel) 6 Maskit st. P.O.B. 3007, Herzlia 46104, Israel Tel. (972)52-522261 amos%nsta@nsc.com {hplabs,pyramid,sun,decwrl} 34.48'E 32.10'N
manis@ubc-cs.UUCP (04/21/87)
In article <658@edge.UUCP> doug@edge.UUCP (Doug Pardee) writes: >> You left off reason (e), I hope, and that is "If you want Readability and >> therefore Maintainability". > >A C program is no more readable to a C programmer than an assembler program >is to an assembler programmer. Ditto for maintainability. The issues of >Readability and Maintainability come back to points (c) and (d) above; in >other words, whether we're talking about C programmers or assembler >programmers. I must respectfully disagree with these remarks. Admittedly much of the C I have seen (say in mod.sources) is disgracefully written. However, I write C as if it were Pascal. I am also a quite competent assembler programmer (for several *dozen* different machines). I can read my C and Pascal code; I cannot read my assembly code anywhere as well, even when it is carefully written. >The notorious lack of "commenting" by supposedly professional C programmers >really compounds this problem. Professional assembler programmers make dang >sure their code is well commented, and the comments are maintained as the >program is maintained. Comments are not very useful in programming. I once maintained a BCPL compiler which had almost no comments in it. The front end (parser) was a model of clarity; the back end (code generator) was tangled, contorted and used an immense number of coding tricks (it generated very good code, though). The difference was the programmers; no number of comment lines would have made that code generator clear. >> You forgot >> >> e) Reducing the opportunity for bugs by roughly a factor of 10. > >I'd like to see some studies on this. Take a look through the back issues of IEEE Transactions on Software Engineering. All other things being equal, the number of bugs is generally directly proportional to the number of source lines. >... C is basically a PDP-11 assembler in a fancy suit, and brings >with it all of the screw-up possibilities that you get in real assembler. Where does this strange idea come from? The newest trends in C compilers are to very fussy type-checking (which is where such things as function prototypes originate). Admittedly, C compilers can't detect subscript range violations, but just about all type errors can be detected by some of the better compilers, or by lint. >... C zealots usually >deny that there exist any applications for which C is a poor fit. I'm certainly not a C zealot, but I can't think of *any* application for which C is a poor choice as a language but assembler is a good one. Of course, that does not mean that a particular C compiler will give code of adequate efficiency. >Furthermore, C is more difficult to debug than assembler, because (like >all other high-level languages) it is distanced from the machine. Well, dbx certainly reduces that distance. On the other hand, I know that I write C programs with a lot fewer errors than my assembler programs, and therefore my C programs don't make as many trips to the debugger. Mind you, I use lint a lot on UNIX systems, and the C compiler I use on my micro (Mark Williams C for the Atari ST) does a very good job of type-checking. Doug goes on to remark that C programmers just switched from Basic. Indeed, there are many incompetent C programmers, just as there are many incompetent assembler programmers (many of the latter are engineering graduates who had just *one* programming course). Has nothing much to do with anything, as far as I can see. Doug, if you want to program in assembler, then by all means do so. But please don't attack C because it isn't assembler. I agree that the quality of much C code is poor; but if you care about this matter, are you out there running structured programming courses for these people? ----- Vincent Manis {seismo,uw-beaver}!ubc-vision!ubc-cs!manis Dept. of Computer Science manis@cs.ubc.cdn Univ. of British Columbia manis%ubc.csnet@csnet-relay.arpa Vancouver, B.C. V6T 1W5 manis@ubc.csnet (604) 228-6770 or 228-3061 "Long live the ideals of Marxism-Lennonism! May the thoughts of Groucho and John guide us in word, thought, and deed!"
hrubin@osupyr.UUCP (Herman Rubin) (04/22/87)
I have found it necessary to include the entire article for the convenience of the reader; I have placed it at the end. I have frequently encountered situations where the operations I wish to use are extremely difficult in the totally inadequate HLL's available. In other situations, the problem is a (frequently vast) choice of algorithms; the programmer who thinks in BASIC or FORTRAN or C cannot begin to appreciate what can be done. I am inclined to doubt that most of them retain the ability to understand what a computer can do if its instruction capability is utilized. I find machine language easy to understand, even easier than the weird constructs of the HLL's. The difficulty of writing good programs is the now unnecessary awkwardness of assembler constructs. If an intelligently designed assembler, or even macro translator, were available, this could be done. Alternatively, if the intelligent and resourceful programmer could define his types, define operations (e.g., define "`\'" to be the "bit clear" operation on most machines, and to inform the compiler that this is a hardware operation with a syntax similar to the other logical operations, or define ">>>" and "<<<" to be double register shifts), use the condition codes instead of the restricted "?" in C (how do you use integer overflow? I want to use it), allow the programmer to force things to be in registers or even short register vectors, etc., we may reach the stage that a HLL may be used for intelligent programming. Learning the op-codes (and their execution times and overlap properties) is not sufficient, but it is necessary. Does learning HLL thinking prevent, and not just inhibit, learning to make a computer do what the user, and not the compiler designer, wants to do? We do not know how to design a good compiler; a flexible "SuperC" may do a fair job. In article <215@gtx.com>, al@gtx.com (0732) writes: > > doug@edge.UUCP (Doug Pardee) writes: > > > consider this: There are 4 basic reasons for writing a particular program > > in C instead of in assembler: > > a) If efficiency is of little consequence -- the program is only going tome > be run once or twice; > > b) If portability is important; > > c) If the programmer is ignorant of assembler; or > > d) If the boss wants "BIC lighter" programmers: cheap, disposable, and > > easily replaceable. > > One important reason not mentioned above is development time. > Unless there are unusual efficiency considerations, The C programmer can > program rings around the assembly language programmer because there > are fewer low-level discriminations to be made. A well-known folk theorem > of computer science says that it takes about as long to write and debug one > line of, say, Fortran or C as one line of assembly language. Since the > assembly language program is considerably longer, it takes longer to write. > > > A C program is no more readable to a C programmer than an assembler program > > is to an assembler programmer. Ditto for maintainability. The issues of > > Readability and Maintainability come back to points (c) and (d) above; in > > other words, whether we're talking about C programmers or assembler > > programmers. > > "Higher-level" languages such as C and Fortran were all designed and > implemented by exceptionally competent ASSEMBLY LANGUAGE PROGRAMMERS > disgusted by the unreadability and unmaintainability of assembly language. > Portability was always a secondary issue. > > > And finally, <<<Break out the fireproof suits!>>> all of the above was > > based on "programmers of equal competency". But consider that point (d) > > above virtually guarantees that the ever-increasing pool of marginally > > competent programmers (you know the ones, "I got me a PeeCee and learnt > > meself how to program in Basic and C") will be hired by penny-pinching > > companies to program in C. > > At least the kid with the PC is educable. Spare me from the > hardware retread who *knows* that all there is to programming is learning > the op-codes for the processor. > > > -------------------------------------------------------------- > | Alan Filipski, GTX Corporation, Phoenix, Arizona 85283, USA | > | ihnp4!arizona!sunburn!gtx!al > -------------------------------------------------------------- > > God took seven days to create the world; > an APL programmer could do it in one line. -- Herman Rubin Until mid May: Department of Statistics, Cockins Hall, 1958 Neil Avenue Ohio State University, Columbus OH43210 hrubin@osupyr or cbosgd!osu-eddie!osupyr!hrubin or ts0474@ohstvma.bitnet "Permanent": Department of Statistics, Purdue University, West Lafayette IN47907 hrubin@l.cc.purdue.edu or ihnp4!pur-ee!stat-l!hrubin or hrubin@purccvm.bitnet
doug@edge.UUCP (Doug Pardee) (04/25/87)
I see no reason to repeat my previous postings on the use of assembler for some non-portable applications. But I would like to expand on a couple of points: > I'm certainly not a C zealot, but I can't think of *any* application for > which C is a poor choice as a language but assembler is a good one. Well, let's see. There are some obvious ones, like real-time life-support or safety-monitor applications in which it is absolutely necessary to show that in the worst case, the response time will be less than x microseconds. (This requires not only assembler language, but also relatively primitive CPUs and system designs in which the hardware performance can be determined exactly, none of this "depends on the percent of cache hits" stuff allowed.) Less obviously, almost anything having to do with character handling. Most CPUs provide hardware instructions for string copies, compares, and searches. C provides no statements which could be compiled into these instructions. Also, anything that has to do with direct hardware manipulation (like device drivers). On the 68000, for instance, the assembler programmer has the MOVEP instruction which allows easy writing of multiple bytes to I/O devices. In C, there's no statement that can do this, so you end up with *(char *)0x12345 = (val >> 8) & 0xFF; *(char *)0x12347 = val & 0xFF; Another reason for writing device drivers in assembler is to have absolute control over when and how the I/O locations are referenced. Trying to program an ordinary 2681/68681 DUART, for instance, you have to have a certain amount of time pass between references. And certain locations are off-limits; you don't want the C compiler generating a >1 byte fetch which accidently includes a no-no byte (this is with memory-mapped I/O, of course). > Of course, that does not mean that a particular C compiler will give code of > adequate efficiency. This is the more important consideration. There's a lot of talk about what compilers *could* do in optimization. And somehow that's gotten translated into the mistaken belief that all of this wonderful optimization is really happening, or will happen soon. The truth is that most C compilers are based on PCC, and produce absolutely terrible code. Any programmer who has only PCC available should *not* believe any of the jive about C code being efficient. And even with the decent optimizing compilers, code size in C is awful. See the discussion in comp.sys.amiga about how to get "hello, world" down from 8K to 1K! In assembler, it'd be maybe 50 bytes. > Doug goes on to remark that C programmers just switched from Basic. I hope that isn't how it sounded. What I was trying to say is that C programming is a rather attractive profession to someone who isn't really a professional-level programmer, and it is just too easy for them to get into. The existence of these people drags down the average quality of C code, and puts heavy strain on salaries and working conditions for *all* C programmers. Don't get lost, I'm getting to a subtle point (I hope). Because there are so many C programmers, who will work for low pay under less-than-thrilling conditions, many employers insist that their employees write in C. Subpoint #1: This really is the employer's right. Subpoint #2: This guarantees that they can get cheap replacements with little effort. Subpoint #3: The employers don't really have to insist too hard, because the "programmers" they hire don't know anything but C anyway. Subpoint #4: This is a great situation for those not-too-competent programmers; even though the pay is low and there's a lot of competition for the jobs, things are a lot worse in the burger-flipping business. Major Point: what is good for the employer and for the not-so-capable programmers is not necessarily in the best interests of genuinely capable programmers. Corollaries: it is also not necessarily in the product's best interests. It is also not necessarily in the customers' best interests (for those cases when the code is part of a product). > please don't attack C because it isn't assembler. Perhaps that's how it sounded, but 'tain't so. I do program in C, a lot of the time. Been doing it for years. I'm not attacking C, I'm attacking the thoughtless use of C in applications where it doesn't belong. C is a fine language for a lot of things, but some people seem to be operating on the age old principle, "If all you have is a hammer, everything looks like a nail." -- Doug Pardee -- Edge Computer Corp. -- Scottsdale, Arizona
gwyn@brl-smoke.ARPA (Doug Gwyn ) (04/26/87)
I tried to ignore this debate, but here goes: In article <682@edge.UUCP> doug@edge.UUCP (Doug Pardee) writes: >Well, let's see. There are some obvious ones, like real-time life-support >or safety-monitor applications in which it is absolutely necessary to show >that in the worst case, the response time will be less than x microseconds. >(This requires not only assembler language, but also relatively primitive >CPUs and system designs in which the hardware performance can be determined >exactly, none of this "depends on the percent of cache hits" stuff allowed.) While sufficient, that approach is not necessary. I know of several real-time applications coded in a variety of high-level languages that work just fine. One just has to know what one is doing. >Less obviously, almost anything having to do with character handling. Most >CPUs provide hardware instructions for string copies, compares, and searches. >C provides no statements which could be compiled into these instructions. This also is not correct. C these days includes a standard run-time support library with a substantial number of string-handling routines; most reasonable implementations make use of special machine instructions when they exist (and when they are faster than ordinary instructions, which amazingly is not always the case). It is even possible to avoid function call overhead and generate in-line code for these routines under most circumstances, although generally it's not worthwhile to do so. >Also, anything that has to do with direct hardware manipulation (like device >drivers). There may occasionally be problems, but I (among others) have written device drivers that port between radically different machine types with several orders of magnitude less work than would be required for assembly- language versions, and performance is quite acceptable. Virtually all UNIX device drivers are written in C. I even find C an easier way to access device registers on my Apple (since such access is only a small fraction of the necessary operations for most device-handling algorithms). >Any programmer who has only PCC available should *not* believe >any of the jive about C code being efficient. Most of us learned long ago that there are better ways to spend our time than trying to squeeze every last drop of performance out of a particular system. There are several kinds of "efficiency", including "programmer efficiency". It's certainly true that C is not always the best choice for every programming project. However, it is usually a pretty good one, and if one has to concentrate on a single language for a random assortment of projects, C is probably a better choice than any other language. Some relevant considerations are availability, portability, efficiency, closeness to the machine, and so on. In spite of much experience in programming in a variety of assembly languages, I do so now only when absolutely necessary (such as in creating run-time support for C compilers). It just isn't good economics to do otherwise. I don't quite understand the argument about C programmers being less skilled than for other languages. It takes MORE skill to be really proficient in C than in languages such as Fortran and BASIC. If you mean that home hobbyists tend to be less than professional, and that they often use C (or BASIC!), then that's probably true. So what? Incompetents will do a much worse job using assembler, and skilled professionals will do a better job using C.
manis@ubc-cs.UUCP (Vincent Manis) (04/26/87)
In article <682@edge.UUCP> doug@edge.UUCP (Doug Pardee) writes, quoting me: >> I'm certainly not a C zealot, but I can't think of *any* application for >> which C is a poor choice as a language but assembler is a good one. >Well, let's see. There are some obvious ones, like real-time life-support >or safety-monitor applications in which it is absolutely necessary to show >that in the worst case, the response time will be less than x microseconds. >(This requires not only assembler language, but also relatively primitive >CPUs and system designs in which the hardware performance can be determined >exactly, none of this "depends on the percent of cache hits" stuff allowed. I said *language*, not *compiler*. It may well be that on a particular machine a particular problem requires the use of assembly language. But there is nothing in the specification of C (or other high-level languages) which mandates they be less efficient. In fact, it is often the case that the use of a high-level language makes possible the implementation of substantially more efficient algorithms than would be reasonable for an assembler programmer. >> Of course, that does not mean that a particular C compiler will give code of >> adequate efficiency. > >This is the more important consideration. There's a lot of talk about what >compilers *could* do in optimization. And somehow that's gotten translated >into the mistaken belief that all of this wonderful optimization is really >happening, or will happen soon. In 1973, when UNIX was rewritten in C, the estimate was that the new system was about 1/3 larger (in space) than the old, though the new system was substantially more powerful. Compilers have gotten a lot smarter since then. >The truth is that most C compilers are based on PCC, and produce absolutely >terrible code. Any programmer who has only PCC available should *not* believe >any of the jive about C code being efficient. Agreed. pcc is not my idea of a good compiler. But we were discussing the language. >And even with the decent optimizing compilers, code size in C is awful. See >the discussion in comp.sys.amiga about how to get "hello, world" down from >8K to 1K! In assembler, it'd be maybe 50 bytes. I'm not an Amiga expert. However, I hope that Doug isn't labelling Lattice C as a decent optimisisng compiler. >Don't get lost, I'm getting to a subtle point (I hope). Because there are >so many C programmers, who will work for low pay under less-than-thrilling >conditions, many employers insist that their employees write in C. If I were a programming manager, I would insist that employees write in a high-level language. Whether this language is C, Modula-2, Pascal, or even (ugh) Ada is not the point. For reasons of efficiency, reliability, and portability, there is simply no alternative. (BTW, employers who want less than the best so they can pay less than the best generally don't last too long, at least in my experience). ----- Vincent Manis {seismo,uw-beaver}!ubc-vision!ubc-cs!manis Dept. of Computer Science manis@cs.ubc.cdn Univ. of British Columbia manis%ubc.csnet@csnet-relay.arpa Vancouver, B.C. V6T 1W5 manis@ubc.csnet (604) 228-6770 or 228-3061 "Long live the ideals of Marxism-Lennonism! May the thoughts of Groucho and John guide us in word, thought, and deed!"
jbuck@epimass.UUCP (Joe Buck) (04/26/87)
In article <682@edge.UUCP> doug@edge.UUCP (Doug Pardee) writes: >> I'm certainly not a C zealot, but I can't think of *any* application for >> which C is a poor choice as a language but assembler is a good one. > >Well, let's see. There are some obvious ones, like real-time life-support >or safety-monitor applications in which it is absolutely necessary to show >that in the worst case, the response time will be less than x microseconds. >(This requires not only assembler language, but also relatively primitive >CPUs and system designs in which the hardware performance can be determined >exactly, none of this "depends on the percent of cache hits" stuff allowed.) Granted. But then you can't use any modern CPU chip, without overspecifying CPU power a good bit. >Less obviously, almost anything having to do with character handling. Most >CPUs provide hardware instructions for string copies, compares, and searches. >C provides no statements which could be compiled into these instructions. Not granted. Library functions (strcpy, strcmp, etc) should be written in assembler to best exploit a particular machine's capabilities (though one can start the project with a C version). ANSI C will provide mechanisms to compile this in-line. >Also, anything that has to do with direct hardware manipulation (like device >drivers). On the 68000, for instance, the assembler programmer has the >MOVEP instruction which allows easy writing of multiple bytes to I/O >devices. In C, there's no statement that can do this, so you end up with > *(char *)0x12345 = (val >> 8) & 0xFF; > *(char *)0x12347 = val & 0xFF; The 68000's notion of "odd bytes only" or "even bytes only" for device registers is ugly enough so you have to use assembler. Gag me! >Another reason for writing device drivers in assembler is to have absolute >control over when and how the I/O locations are referenced. Trying to >program an ordinary 2681/68681 DUART, for instance, you have to have a certain >amount of time pass between references. And certain locations are off-limits; >you don't want the C compiler generating a >1 byte fetch which accidently >includes a no-no byte (this is with memory-mapped I/O, of course). This is an argument for using a mixture of assembly and C. >And even with the decent optimizing compilers, code size in C is awful. See >the discussion in comp.sys.amiga about how to get "hello, world" down from >8K to 1K! In assembler, it'd be maybe 50 bytes. Wrong, since "printf" is written in assembler in most cases. I keep seeing this absolutely bogus argument. The right solution is puts ("Hello, world\n"); which should be about 50 bytes. You should know better, Doug. printf contains code to handle every possible %n.m{s,d,c,f,o,x} that might appear. That's a lot of stuff to drag around when you don't need it. >I hope that isn't how it sounded. What I was trying to say is that C >programming is a rather attractive profession to someone who isn't really a >professional-level programmer, and it is just too easy for them to get into. >The existence of these people drags down the average quality of C code, and >puts heavy strain on salaries and working conditions for *all* C programmers. Oh, crap. I don't think the quality of most assembly code I've run into is really all that high. As Sturgeon said, 90% of everything is crap. A good programmer will produce n lines of working C just as fast as n lines of working assembler. A good programmer will also recognize that the best solution to some of the problems you pose is a mixture of assembler and C, and the more C there is, the fewer bugs the code will have. >Don't get lost, I'm getting to a subtle point (I hope). Because there are >so many C programmers, who will work for low pay under less-than-thrilling >conditions, many employers insist that their employees write in C. Because C can be produced faster, is easier to debug, and, yes, can be done by more people; because C can be written to be portable when done by a knowledgeable programmer, many employers specify C. >Subpoint #1: This really is the employer's right. Subpoint #2: This guarantees >that they can get cheap replacements with little effort. Subpoint #3: The >employers don't really have to insist too hard, because the "programmers" they >hire don't know anything but C anyway. Subpoint #4: This is a great >situation for those not-too-competent programmers; even though the pay is low >and there's a lot of competition for the jobs, things are a lot worse in the >burger-flipping business. I find that people who know too much about the machines they are working on produce worse C! Why? For example, picture a 68000 C with 2-byte ints and 4-byte longs. I had a guy who insisted on using longs instead of pointers. Well, it works, and it's the right size, right? People who are too close to the hardware often tend to build unstructured monstrosities, which, while often fast and small, remind one of the old joke: if architects built buildings the way programmers built programs, the first woodpecker that came along would destroy civilization. Because of the freedom C gives you, it can be a dangerous language for a poor programmer. Really good C programmers are a rare breed and deserve good pay. >Major Point: what is good for the employer and for the not-so-capable >programmers is not necessarily in the best interests of genuinely capable >programmers. I'm not convinced that the people you're calling "genuinely capable programmers" are the same group I would use the term for. How about "overspecialized has-beens"? For many problems, people-time is more expensive, and software maintenance more costly, than some waste in CPU time and memory space. So the C program is twice as big and half as fast as the best possible assembly program. It can be produced in one-third the time, and it's cheaper to maintain, and it's more likely to be correct. And, if done correctly, it can be moved to different hardware quickly and cheaply. If anything, C gives you too much freedom and a more restrictive language might be still better. >Corollaries: it is also not necessarily in the product's best interests. It >is also not necessarily in the customers' best interests (for those cases when >the code is part of a product). Certain applications have to be fast and small, and times have to be predicted exactly. For these applications, use assembler. > "If all you have is a hammer, everything looks like a nail." While you say you use C sometimes, I think assembler is your hammer. I think the group of problems where assembler is appropriate is a good deal smaller than you think it is. -- - Joe Buck {hplabs,ihnp4,sun,ames}!oliveb!epimass!jbuck seismo!epiwrl!epimass!jbuck
bzs@bu-cs.BU.EDU (Barry Shein) (04/27/87)
Posting-Front-End: GNU Emacs 18.41.4 of Mon Mar 23 1987 on bu-cs (berkeley-unix)
Everyone, in retort to Doug Pardee's note about character handling in
C vs Asm mentions library routines (and possibly inline asm.)
How about the now well established structure assignment:
struct string {
char thechars[STRSIZE];
};
If I declare s1 and s2 to be struct strings and do a:
s1 = s2;
my Vax generates a movc3, my Encore (NS32K) generates a MOVSD
instruction, my Sun (68K) generates a tight dbra loop and my IBM3090
generates a MVCL, all of that is quite optimal if you want to save
yourself a trip to the prin-ops.
I think the problem is (if there is one) that most (all?) machine
architectures don't have a lot to deal with null term'd strings. Oh,
you can use a LOCC on a Vax or even a TRT on an IBM (370, not PC),
minor, but most assembler programmers will go for fixed length string
formats that will match the hardware (not a slur, it's the right thing
if you're after raw speed and can stand some loss in flexibility.)
I can't argue with the success of C's null terminated string formats,
but I've coded in a BCPL string style in C programs to speed up certain
operations and I still have all 10 of my fingers.
It just doesn't often matter much (tho you want to profile strcpy()
when your text processing slows down, you might change your mind.)
-Barry Shein, Boston University
mwm@eris.BERKELEY.EDU (Mike (My watch has windows) Meyer) (04/27/87)
In article <682@edge.UUCP> doug@edge.UUCP (Doug Pardee) writes: >And even with the decent optimizing compilers, code size in C is awful. See >the discussion in comp.sys.amiga about how to get "hello, world" down from >8K to 1K! In assembler, it'd be maybe 50 bytes. > >-- Doug Pardee -- Edge Computer Corp. -- Scottsdale, Arizona You might make 50 bytes, Doug. But I'd be willing to bet against it. There's more than 500 bytes of overhead in that C program that re-arranges the environment to look like Unix. A lot of this you won't be able to avoid. If you're not used to OS's that consist of cooperating processes, some of it is liable to surprise you. At one point in the past, a friend and I had a contest to produce the shortest executable file to do a simple task (continously output a string of C-G's to stdout) on a v6 Unix system. As I recall, it was a draw. His carefully tailored assembler program, with the a.out header hand-stripped from it, was the same size as my shell script - 17 bytes. Of course, I can produce a smaller shell script now..... <mike -- Take a magic carpet to the olden days Mike Meyer To a mythical land where everybody lays ucbvax!mwm Around in the clouds in a happy daze mwm@berkeley.edu In Kizmiaz ... Kizmiaz mwm@ucbjade.BITNET
doug@edge.UUCP (Doug Pardee) (04/27/87)
// Note to the net members: I realize this discussion is getting pretty far afield for a "C" discussion forum, and this posting doesn't help much. I rationalize it only in that it relates to when to use and when not to use C. // I'd like to expand upon the comment > ... The difficulty of writing good programs is the > now unnecessary awkwardness of assembler constructs. If an intelligently > designed assembler, or even macro translator, were available, this could > be done. I kinda suspect this is one of the big reasons that many people think that assembly programming is difficult: the assembler software they're using is terrible. In particular, most U*ix-based assemblers contain only the bare minimum features needed in order to assemble the output of PCC. Imagine if you had to use a C compiler which was designed only to compile output from the FORTRAN compiler. Six-character (all caps) variable names, no char variables, no shifts or logical operations, no pointers, no unions nor structures!! And the coup de grace, *no preprocessor*. If this "brain-damaged" compiler was the only C compiler you'd ever seen, I wouldn't be surprised if you thought that C was a difficult and cryptic language. I have yet to see an assembler for a microprocessor which has the functionality of mainframe assemblers written a quarter century ago. The closest is the Microsoft Macro Assembler for the PC, and it has the major deficiency of not being able to deal with macro libraries (not to mention the fact that it necessarily has to assemble iAPX86 code :-). The best assembler translator program that I've ever used was (cover your ears, kiddies, I'm gonna say a naughty word) the IBM 360/370 OS assembler. Just about everything you'd ever want was in that assembler. Not always in the nicest syntax, but at least it was there. But that assembler is 25 years old now! -- Doug Pardee -- Edge Computer Corp. -- Scottsdale, Arizona
doug@edge.UUCP (04/28/87)
// Note to the net: This is getting out of hand. I really *am* trying to keep this to a minimum, and trying to avoid "is/is not/is so" arguments. // I think I gave the wrong impression: > > I'm certainly not a C zealot, but I can't think of *any* application for > > which C is a poor choice as a language but assembler is a good one. > me>Well, let's see. There are some obvious ones, like real-time life-support me>or safety-monitor applications in which it is absolutely necessary to show me>that in the worst case, the response time will be less than x microseconds. > > I said *language*, not *compiler* ... > there is nothing in the specification of C (or other high-level languages) > which mandates they be less efficient. I wasn't referring to efficiency. I was referring to predictability. I can look in my book here and find that on a 10MHz 68000, the instruction MOVE.W 6(A0),D0 will take exactly 1.6+.1w microseconds, for a "w" wait state memory. I haven't the vaguest idea how long it will take to execute temp1 = ptr1->count; and what's worse, a change to some other part of the same module could cause this statement to be faster or slower (as the result of global optimization). Okay? -- Doug Pardee -- Edge Computer Corp. -- Scottsdale, Arizona
amos@instable.UUCP (Amos Shapir) (04/29/87)
In article <685@edge.UUCP> doug@edge.UUCP (Doug Pardee) writes: >I kinda suspect this is one of the big reasons that many people think that >assembly programming is difficult: the assembler software they're using is >terrible. In particular, most U*ix-based assemblers contain only the bare >minimum features needed in order to assemble the output of PCC. > ... >I have yet to see an assembler for a microprocessor which has the functionality >of mainframe assemblers written a quarter century ago. So, people do not like assembler because they have no macros - ok, let's give them named macros to name their constructs, and macro libraries, and why not recursive macros so they can use nested IF/WHILE macros - and Voila! you have created an almost HLL syntax, but unlike a 'real' HLL, the generated code is ugly and inefficient, and you do not have the security of type checking. The syntax of early dialects of C suggest that it also strated that way. Then it became popular and people started to port it to different architectures. This required stronger definitions than just the 'whatever your hardware does' of early C, adding more keywords and constructs to the language. Now we have come around a full circle, and people want a 'back to earth' small language (as is evident by articles describing the SPL language in comp.lang.misc yesterday, or the 800-line FOOGOL compiler posted to net.sources last month). Is that the end of carefree C as we know it? -- Amos Shapir National Semiconductor (Israel) 6 Maskit st. P.O.B. 3007, Herzlia 46104, Israel Tel. (972)52-522261 amos%nsta@nsc.com {hplabs,pyramid,sun,decwrl} 34.48'E 32.10'N
hrubin@osupyr.UUCP (Herman Rubin) (05/05/87)
In article <757@instable.UUCP>, amos@instable.UUCP (Amos Shapir) writes: > In article <685@edge.UUCP> doug@edge.UUCP (Doug Pardee) writes: > >I kinda suspect this is one of the big reasons that many people think that > >assembly programming is difficult: the assembler software they're using is > >terrible. > > So, people do not like assembler because they have no macros - ok, let's > give them named macros to name their constructs, and macro libraries, > and why not recursive macros so they can use nested IF/WHILE macros - > and Voila! you have created an almost HLL syntax, but unlike a 'real' > HLL, the generated code is ugly and inefficient, and you do not have the > security of type checking. > > Amos Shapir > National Semiconductor (Israel) > 6 Maskit st. P.O.B. 3007, Herzlia 46104, Israel Tel. (972)52-522261 > amos%nsta@nsc.com {hplabs,pyramid,sun,decwrl} 34.48'E 32.10'N Both of these posters miss the point. I do not object to typing, but I do to strong typing. The macro processors that I have seen are inadequate. I would like x = y - z to be a macro, where the translation into the appropriate code would depend on the types of x, y, and z. However, I should be able to override this if I, the person who knows what I am trying to do, think it appropriate. I want to be able to be able to use such constructs as multiple words, multiple word shifts, condition codes (including overflows), etc. I may even have to introduce additional macros, such as a triple word shift or an alternative to it on machines which require even-odd register pairs. I should be able to specify the k-th most significant word or byte of a multi-unit construct without having to worry whether the machine is little or big endian when that can be done. I know the benefits and dangers of using boolean operations on floating point numbers, and know that machine dependence is frequently necessary to get any efficiency. As for the generated code being ugly and/or inefficient, there are few cases in which compilers have produced code which is any better than the way I would code the problem. I am not against compilers and HLLs provided they allow the programmer to easily override the bad code they produce. Also remember that the cost of subroutines is high and the cost of transfers is not low; the cost of memory references is also not too good. I think a fair compiler/ assembler can be produced. I also believe that anyone who attempts to produce a good language/compiler/assembler can only produce a bad product. All mankind does not know enough to restrict the intelligent programmer; the current attempts only brain-damage. -- Herman Rubin Until mid May: Department of Statistics, Cockins Hall, 1958 Neil Avenue Ohio State University, Columbus OH43210 hrubin@osupyr or cbosgd!osu-eddie!osupyr!hrubin or ts0474@ohstvma.bitnet "Permanent": Department of Statistics, Purdue University, West Lafayette IN47907 hrubin@l.cc.purdue.edu or ihnp4!pur-ee!stat-l!hrubin or hrubin@purccvm.bitnet