Expert C Programming Deep C Secrets (C 专家编程 英文版 完整目录 书签) 网上只有这一个290页的英文版本,都没有目录……手工加入目录……The $20 Million BugIn Spring 1993, in the Operating system development group at Sun Soft, we had a"priority one" bureport come in describing a problem in the asynchronous I/O library. The bug was holding up the saleof S20 million worth of hardware to a customer who specifically needed the library functionality, Sowe wcrc cxtrcmcly motivated to find it. After somc intcnsive debugging sessions, the problem wasfinally traced to a statement that readx==2It was a typo for what was intended to bc an assignment statement. Thc programmer s finger hadbounced on the"equals "key, accidentally pressing it twice instead of once. The statement as writtencompared x to 2, generated true or false, and discarded the resultC is enough of an expression language that the compiler did not complain about a statement whichevaluated an expression had no side-effects and simply threw away the result we didn t knowwhether to bless our good fortune at locating the problem, or cry with frustration at such a commontyping error causing such an expensive problem. Some versions of the lint program would havedetected this problem, but it's all too easy to avoid the automatic use of this essential toolThis book gathers together many other salutary stories. It records the wisdom of many experiencedprogrammers, to save the reader from having to rediscover everything independently. It acts as a guidefor territory that, while broadly familiar, still has some unexplored corners. There are extendeddiscussions of major topics like declarations and arrays/pointers, along with a great many hints andmnemonics. The terminology of ANSi C is used throughout, along with translations into ordinaryEnglish where neededProgramming ChallengeORHandy HeuristicSample BoxAlong the way, we have Programming Challenges outlined in boxes like this oneThese are suggestions for programs that you should writeThere are also handy Heuristics in boxes of their ownyour own. Or you can ignore them if you already have your own guidelines that you like pThese are ideas, rules-of-thumb, or guidelines that work in practice. You can adopt thembetterConventionOne convention that we have is to use the names of fruits and vegetables for variables (only in smallcode fragments, not in any real program, of course)char pear[40]idouble peachint mango =13ong melon= 2001iThis makes it casy to tcll what's a C rescrved word, and what's a namc thc programmer suppliedSome people say that you can' t compare apples and oranges, but why not--they are both hand-heldround edible things that grow on trees. Once you get used to it, the fruit loops really seem to helpThcrc is onc othcr convcntion--somctimcs wc rcpcat a kcy point to cmphasizc it In addition, wcsometimes repeat a key point to emphasize itLike a gournet recipe book, Expert C Programming has a collecTion of tasty morsels ready for thereader to sample. Each chapter is divided into related but self-contained sections; it's equally easy toread the book serially from start to finish, or to dip into it at random and review an individual topic atlength. The technical delails are sprinkled with many true stories ofhow C programming works inpractice. Humor is an important technique for mastering new material, so each chapter ends with alight relief"section containing an amusing C story or piece of software folklore to give the reader achange of paceReaders can use this book as a source of ideas, as a collection of c tips and idioms, or simply to learnmore about ANSI C, from an experienced compiler writer. In sum, this book has a collection of usefulideas to help you master the fine art of ANSI C. It gathers all the information, hints, and guidelinestogether in one place and presents them for your enjoyment. So grab the back of an envelope, pull outyour lucky coding pencil, settle back at a comfy terminal and let the fun beginSome Light Relief--Tuning File SystemsSome aspects of C and UNIX are occasionally quite lighthearted. There's nothing wrong with welllaced whimsy. The IBM/ Motorola/Apple power Pc architecture has an E I.E. I.O. instructionthatstands for Enforce In-order Execution of 1/0". In a similar spirit, there is a uNIX command,tune fs, that sophisticated system administrators use to change the dynamic parameters of afilesystem and improve the block layout on diskn Probably designed by some old farmer named McDonaldThe on-line manual pages of the original tunefs, like all Berkeley commands, ended with a"Bugssection. In this case. it readBugsThis program should work on mounted and active file systems,but it doesnt. Because the superblock is not kept in thebuffer cache, the program will only take effect if it is runon dismounted file systems; if run on the root file system,the system must be rebooted. You can tune a file system, butyou cant tune a fishEven better the word-processor source had a comment in it threatening anyone who removed that lasthrase! It saidTake this out and a UNIX Demon will dog your steps from nowuntil the time t's wrap aroundWhen Sun, along with the rest of the world changed to SVr4 uNiX, we lost this gcm. The S Vr4manpages don,'t have a" Bugs"section-they renamed it"Notes"(does that fool anyone? The"tunafish" phrase disappeared, and the guilty party is probably being dogged by a uNiX demon to this dayPreferably lpdProgramming ChallengeComputer DatingWhen will the time t's wrap around?Write a program to find out1. Look at the definition of time t. This is in file /usr/include/time. h2. Code a program to place the highest value into a variable of type time t, thenctime has nothing to do with the language C, it just means"convert time, sBpass it to ctime() to convert it into an ASCiI string. Print the string. Note thatFor how many years into the future does the anonymous technical writer who removed thecomment have to worry about being dogged by a UNIX daemon? Amend your program tofind out1. Obtain the current time by calling time ()2. Call difftime () to obtain the number of seconds between now and the highestvalue oftime t3. Format that value into years, months, weeks, days, hours, and minutes. Print itIs it longer than your expected lifetime?Programming SolutionComputer DatingThe results of this exercise will vary between PCs and UNIX systems, and will depend onthe way time t is stored. On Sun systems, this is just a typedef for long. Our first attemptedsolution is#include #include int main([time t biggest =0X7FFFFFFFprintf("biggest =%s \ n", ctime(&biggest))ireturn OThis gives a result ofbiggest- Mon Jan 18 19: 14: 07 2038However, this is not the correct answer! The function ctime()converts its argument intolocal time, which will vary from Coordinated Universal Time(also known as GreenwichMean Time), depending on where you are on the globe. California, where this book waswritten,is eight hours behind London, and several years aheadWe should really use the mtime() function to obtain the largest UTC time value. Thisfunction doesnt return a printable string, so we call asctime()to get this. Putting it alltogether,our revised program is#include #include int main(time t biggest=0x?FFFFFFFprintf("biggest = s \n", asctime(mtime( &biggest)))return 0:This gives a result of:biggest Tue Jan 19 03: 14: 07 2038There! Squeezed another eight hours out of itBut we're still not done. If you use the locale for New Zealand, you can get 13 more hours,assuming they use daylight savings time in the year 2038. They are on dSt in Januarbecause they are in the southern hemisphere New Zealand because of its easternmosposition with respect to time zones, holds the unhappy distinction of being the first countryto encounter bugs triggered by particular datesEven simple-looking things can sometimes have a surprising twist in software. And anyonewho thinks programming dates is easy to get right the first time probably hasn' t done muchof itChapter 1. C Through the Mists of TimeC is quirky, flawed, and an enormous successDennis ritchiethe prehistory of C.. the golden rule for compiler-writers.. early experiences with C. the standardyO library and C preprocessor. K&r C. the present day: ANSI C., it's nice, but is it standard?. . thestructure of the ANSI C standard. . reading the ANSI C standard for fun, pleasure, and profit.howquiet is a"quiet change"?.some light relief-the implementation-defined effects of pragmasThe prehistory of cThe story of C begins, paradoxically, with a failure. In 1969 the great Multics project-a joint venturebetween General Electric, MIT, and Bell Laboratories to build an operating system-was clearly introuble. It was not only failing to deliver the promised fast and convenient on-line system, it wasfailing to deliver anything usable at all. Though the development team eventually got Multics creakinginto action, they had fallen into the same tarpit that caught IBM with OS/360. They were trying tocreate an operating system that was much too big and to do it on hardware that was much too smallMultics is a treasure house of solvcd engincering problems, but it also paved the way for c to showthat small is beautifulAs the disenchanted Bell Labs staff withdrew from the multics project, they looked around for othertasks. One researcher, Ken Thompson, was keen to work on another operating system, and madeseveral proposals(all declined)to Bell management. While waiting on official approval, Thompsonand co-worker Dennis ritchie amused themselves porting Thompsons"Space Travel "software to alittle-used PDP-7. Space Travel simulated the major bodies of the solar system, and displayed them ona graphics screen along with a space craft that could be piloted and landed on the various planets. Atthe same time, Thompson worked intensively on providing the PDp-7 with the rudiments ofa newoperating system, much simpler and lighter-weight than Multics. Everything was written in assemblerlanguage. Brian Kernighan coined the name"UNIX in 1970, paro-dying the lessons now learnedfrom multics on what not to do. Figure 1-1 charts early C, UNIX, and associated hardwareFigure 1-1. Early C, UNIX, and Associated Hardware1965719B919711972-3VariousBCPLBNow BEarly cinluencesLarOperating SystUNIX (writon inUNIX (writon inUNIXPDP.7 assembler)PDP11 assemberin CHardwarePDP-7PDP-11BM360HoneywellIn this potential chicken-and-egg situation, uNIX definitely came well before C (and it's also whyUNIX SyStem time is measured in seconds since January 1, 1970-that's when time began). Howeverthis is the story not of poultry, but of programming. Writing in assembler proved awkward: it tooklonger to code data structures, and it was harder to debug and understand. Thompson wanted theadvantages of a high-level implementation language, but without the Pl/I performance andcomplexity problems that he had seen on Multics. After a brief and unsuccessful flirtation withFortran, Thompson created the language b by simplifying the research language BCPL 2 so itsinterpreter would fit in the PDP-7's 8K word memory. B was never really successful; the hardwarememory limits only provided room for an interpreter, not a compiler. The resulting slow performanceprcvcntcd b from bcing uscd for systcms programming of UNIX itsclf.1 The difficulties involved in learning, using, and implementing PL/l led one programmer to pen this verseIBM had a PL/l/ Its syntax worse than JoSs/ And everywhere this language went /It was a total loss uJOSS was an earlier language, also not noted for simplicity[2]BCPL: A Tool for Compiler Writing and System Programming, Martin Richards, Proc. AFIPS Spring JointComputer Conference, 34(1969), pp. 557-566 BCPL is not an acronym for the Before C ProgrammingLanguage, though the name is a happy coincidence. It is the "Basic Combined Programming Lan-guag"basic" in the sense of"no frills"and it was developed by a combined effort of researchers at London geUniversity and Cambridge University in England. A BCPL implementation was available on MulticsSoftware DogmaThe Golden Rule of Compiler-WritersPerformance Is (almost EverythingPerformance is almost everything in a compiler. There are other concerns: meaningful errormessages,good documentation, and product support. These factors pale in comparison withthe importance users place on raw speed. Compiler performance has two aspects: runtimeperformance(how fast the code runs) and compile time performance (how long it takes togenerate code).Runtime performance usually dominates, except in development and studentenvironmentsMany compiler optimizations cause longer compilation times but make run times muchshorter. Other optimizations(such as dead code elimination, or omitting runtime checksspeed up both compile time and run time, as well as reducing memory use. The downside ofaggressive optimization is the risk that invalid results may not be flagged. Optimizers arevery careful only to do safe transformations, but programmers can trigger bad results bywriting invalid code(e.g, referencing outside an array's bounds because they"know"thatthe desired variable is adjacent)This is why performance is almost but not quite everything-if you dont get accuratresults, then it's immaterial how fast you get them. Compiler-writers usually provide apiler options so each programmer can choose the desired optimizations. B's lack ofsuccess, until Donnis Ritchic crcatcd a high-pcrformancc compiled vcrsion called"Now Billustrates the golden rule for compiler-writersB simplified bCPl by omitting some features(such as nested procedures and some loop-ingconstructs) and carried forward the idea that array references should"decompose"into pointer-plus-offset references. B also retained the typelessness of BCPL; the only operand was a machine wordThompson conceived the + and --operators and added them to the b compiler on the PDp-7. Thepopular and captivating belief that they're in c because the pdp-11 featured corresponding auto-increment/decrement addressing modes is wrong! Auto increment and decrement predate the PDp-11hardware, though it is true that the c statement to copy a character in a string大s++;can be compiled particularly efficiently into the PDP-11 codemovb(r0)+,(r1)+leading some people to wrongly conclude that the former was created especially for the lattera typeless language proved to be unworkable when development switched in 1970 to the newlyintroduced PDP-ll. This processor featured hardware support for datatypes of several different sizes,and the b language had no way to express this. Performance was also a problem, leading Thompson toreimplement the os in PDP-1l assembler rather than B. Dennis ritchie capitalized on the morepowerful PDP-11 to create"New B, "which solved both problems, multiple datatypes, andperformance. "New b"the name quickly evolved to"C"was compiled rather than interpreted, andit introduced a type system, with each variable described in advance of useEarly Experiences with CThe type system was added primarily to help the compiler-writer distinguish floats, doubles, andcharacters from words on the new PDP-1 1 hardware. This contrasts with languages like Pascal, wherethe purpose of the type system is to protect the programmer by restricting the valid operations on adata item. With its different philosophy, C rejects strong typing and permits the programmer to makeassignments between objects of different types if desired. The type system was almost an afterthought.never rigorously evaluated or extensively tested for usability. To this day, many C programmersbelieve that"strong typing" just means pounding extra hard on the keyboardMany other features, besides the type system, were put in C for the c compiler-writer's benefit(andwhy not, since C compiler- writers were the chief customers for the first few years). Features of C thatseem to have evolved with the compiler-writer in mind are:Arrays start at 0 rather than 1. Most people start counting at l, rather than zero Compilerwriters start with zero because were used to thinking in terms of offsets. This is sometimestough on non-compiler-writers; although a [ 100] appears in the definition of an array, you'dbcttcr not store any data at a [ 100], sincc a [o] to a[ 99] is the extcnt of the arrayThe fundamental c types map directly onto underlying hardware. There is no built-incomplex-number type, as in Fortran, for example. The compiler-writer does not have to investany effort in supporting semantics that are not directly provided by the hardware. C didn 'tsupport floating-point numbers until the underlying hardware provided itThe auto keyword is apparently useless. It is only meaningful to a compiler-writermaking an entry in a symbol table-it says this storage is automatically allocated on enteringthe block(as opposed to global static allocation, or dynamic allocation on the heap). Auto isirrelevant to other programmers, since you get it by defaultArray names in expressions"decay into pointers. It simplifies things to treat arrays aspointers. We don't need a complicated mechanism to treat them as a composite object, orsuffer thc inefficiency of copying everything when passing thcm to a function. But don't makcthe mistake of thinking arrays and pointers are always equivalent; more about this in ChapterFloating-point expressions were expanded to double-length-precision everywhereAlthough this is no longer true in ANSI C, originally real number constants were alwaysdoubles, and float variables were always converted to double in all expressions. The reasongh we'vc ncvcr sccn it appear in print had to do with PDp-l1 floating-point hardwarcFirst, conversion from float to double on a PDP-11 or a VAX is really cheap: just append anextra word of zeros. To convert back just ignore the second word Then understand that somePDP-1l floating-point hardware had a mode bit, so it would do either all single-precision orall double-precision arithmetic, but to switch between the two you had lo change modes