Imagine you are a construction worker,and your boss tells you to connect the gas pipe in the basement to the street's gas main.You go downstairs, and find that there's a glitch;this house doesn't have a basement.Perhaps you decide to do nothing,or perhapsyou decide to whimsically interpret your instructionby attaching the gas main to some other nearby fixture,perhaps the neighbor's air intake.Either way, suppose you report back to your boss that you're done.
KWABOOM!When the dust settles from the explosion, you'd be guilty of criminal negligence.
Yet this is exactly what happens in many computer languages.In C/C++, the programmer (boss) can write "house"[-1] * 37
"house"[-1]
(one which may vary each time the program runs!, and which can'tbe predicted by the programmer),(See also: a blog post by one Alex Gaynor, Modern C++ Won't Save Us.)
This is only one example of how C and C++ get some of the basics wrong.Even the authors of the definitive C++ Annotated Reference Manual (“ARM”)confess that there are problems with the basics (for example,“the C array concept is weak and beyond repair” [pg 212]).I highly recommend C++?? : A Critique of C++for a detailed exposition of flaws (major and minor) of both Cand C++.
For a technical critique of C/C++ from systems/compiler perspective(about the inherent danger of "undefined behavior"and how it arises surprisingly often even in innocuous C/C++ programs)see this excellent series of blog posts.
I'm not saying low-level programming is bad.But when learning how to program, the important thought processshould be on how to take a problem-description to code, and not onhow the machine stores bits.Low-level programming is very important for programmers who interface write devicedrivers, and for compiler writers, etc. But these applications account for a very small portion of all programs written. Let beginning programmers learn the fundamentals,and then those particular students who need it cantake a later course in low-level programming.
Unlike some languages, C and C++ are extremely permissive aboutwhat is a legal program. This flexibility might be nice for professionals,but for beginners it just means that typos tend to cause mysteriousbehavior, rather than signalling errors. In my teaching experience,I've often seen students baffled for hours, becausethey accidentally used a comma somewhere, rather than a semicolon.They often flail for hours, randomly adding or removing keywords they've heard of, like static or public or &, and seeing if that happens to solve their problem.This sort of flailing doesn't help anybody learn, and it's the result of a language which assumes the programmer doesn't ever make mistakes or need help.
A language for students should flag advanced or ambiguous constructs as probable typos.For instance, it's not obvious that in i = v[i++]
,the final value of i
is undefined [C++ ARM, p.46].It's not difficult for a language to warn you if you write this,but no C++ compilers choose to.
In Mathematica, two billion plus two billion is four billion.In Java, it's defined to always be -293 million (approx).In C/C++, it's defined to be whatever answer gets returned,and will vary from machine to machine.
Similarly, an example from the Java Langauge Specification p. 308:“it is not correct that 4.0*x*0.5 [is the same as] 2.0*x;while roundoff happens not to be an issue here, there are large values ofx for which the first expression produces infinity (because of overflow) but the second expression produces a finite result.”(Again, the Java spec at least defines what the answer should be inall cases, unlike C++ where this is left to vary between platforms.)
The point is not that there are good reasons why some languageschoose (unlike Mathematica or Scheme) to use imperfect arithmetic,but rather that when teaching a student how to decompose a probleminto functions and how to program effectively,it's purely a digression to have to talk about numeric issuesstemming from the language's choice of internal representation of numbers.This approach encourages the view that programming is a low-level activity,contradicting 60 years of working towards higher-level languages.
Given these known flaws with C/C++, why is there thepopular misconception — among too many programmers and publicalike — that C++ is a good language?I genuinely am at a loss to explain it.But here's my suspicion:When C/C++ programmers, used to walking the tightrope without a net,see that a language like Java or Scheme is doing extra work(verifying that any additions really are given numbersinstead of strings,making sure arrays indices are legal, etc.),their reaction is “ugh, the computer is doing so much extra work,my programs will run too slow!”Indeed, benchmark programs do run faster in C or C++.
But there are a number of things to keep in mind:It is well-documented that development time is much longer in C/C++, since bugs creep in more easily.Hence, cost is also higher for C/C++ programs.(Many C/C++ projects have never been completed because of obscure memory bugs.)I'd rather have a slower, correct program than one which findsa wrong answer more quickly :-).
Or even, how important is it to have fast programs?I don't know about you, but when I think about it,most of my wait-time behind the computer is due to my slow typing,or thinking, or waiting for info to download.I've spent much less time waiting for a calculation to finishthan I have waiting for my computer to re-boot,or re-typing data which was lost because of a crash.(At the current moment, my netscape is unusable,complaining about pointer-based errors“invalid Pixmap” and “invalid GC parameter”. I'll have to try re-installing. Grrr.)
This is not to say that some applications require high performance —voice recognition, drafting, visualization of real-time CAT scan data,modeling star evolution or wind tunnels.Yes, C/C++ can sometimes give that performance better than other languages.And expert programmers using C/C++for those situations is fine.Indeed, taking prototype code and compiling or re-implementing themfor efficiency is one of the prime goals of computer scientists.But such programming (and intensive debugging) is not the best place for the effort of an astronomer or medical researchers.Myself, I rarely or never run those types of programs; most of my time waiting on the computer is waiting for a page to download, not a slow program.
After talking repeatedly with people who tout C++'s run-time efficiency while dismissing its lack of safety,I've seen that they often have a couple of other attitudes:
Writing large software systems bug-free is still a task the industryis learning. But having casual programmers learn C or C++,instead of a high-level language, is not the answer!
For a much more detailed argument on the shortcomings of C and C++, seeIan Joyner'sC++?? : A Critique of C++,which includes examples of bothflaws inherited from Candflaws introduced in C++.For example, he correctly points out that constructs like:
// s1, s2 are char* // (intended as strings, not ptrs to an individual char). while (*s1++ = *s2++);might look optimal to C programmers, but are the antithesis of efficiency. Such constructs preclude compiler optimisation for processors with specific string handling instructions. A simple assignment is better for strings, as it will allow the compiler to generate optimal code for different target platforms. If the target processor does not have string instructions, then the compiler should be responsible for generating the above loop code, rather than requiring the programmer to write such low level constructs. The above loop construct for string copying is contrary to safety, as there is no check that the destination does not overflow, again an undetected inconsistency which could lead to obscure failures. The above code also makes explicit the underlying C implementation of strings, that are null terminated. Such examples show why C cannot be regarded as a high level language, but rather as a high level assembler.
You can certainly findsupportersof C++.But they tend to either misunderstand issues, or have a more relaxed attitude towards unnecessary bugs in commercial products.For instance, choosing a random page from the above link, we find theassertion
ANSI C makes type safety optional. C++ makes it mandatory. In C++ itis very difficult (not impossible) to violate the type system.Excuse me?Type casting — which theoretically should be avoided, but is found allover C++ code (under the name of expediency: devotion to efficiency at the expense of correctness) — type casting annihiliates any pretense of type safety:
class Party { /* ...class details... */ };class Trouble { /* ...class details... */ };Party *invitation = (Party*) (new Trouble()); |
invitation
points to a Party
, when in fact it points to a Trouble
.As soon as the programmer tries using the variable invitation
,an error will occur. If they're lucky, the program will crash;if unlucky they'll proceed without knowing they are working with garbage.(This example is in no way atypical C/C++ code.)The above paper, after erroneously claiming C++ is “mostly” type-safe,does acknowledge that lack of type-safety is an anathema:...type errors in C are often the causes ofstrange bugs that take weeks or months to find, and that exhibittransient and misleading behavior. They often foul the stack or heapand cause eventual failure several million instructions after theprecipitating event. Such bugs are the hallmark of poor qualitysoftware.Why use a language which admits the possibility of such“poor quality software”? C and C++ demonstrate that whena language allows poor practices, thousands of programmerswill embrace such practices.
The above citation also asserts:
Why did C succeed? Because it cut through all the crap. Instead offighting for “purity”, the authors of C created a language that could beused. They never contended that it was perfect or pure,If by succeed, you mean “many programs were written in it,many had bugs which required a lot of effort before theprogram was released, and still contained significant flaws”,then sure. More insidiously, C's prevalence has been responsible forthe culture of thinking that bugs are acceptable.Already mentioned is the additional costs in increased production,failed projects, and lost work.There are more dramatic examples; one that touched me personallywas theinternet worm of '88.It stopped all work in engineering departments around the country,since most mainframes were turned off for a couple days,while experts from around the country gathered in Berkeley to find the problem.The opening which the hacker exploited?A buffer overflow in
finger
,a core program run on most all UNIX computers.While this particular bug is from 1988,try right now a web search for “(buffer OR stack) overflow bug”;I just got 72,000 hits on pages which have discussing specific bugs of this one sort(2001.jan)(including serious security breaches in programs likeMicrosoft MessengerandAOL Instant Messenger, used by millions).All stemming from C's low-level “feature” of allowing arbitrary memory accessw/o security checks.And there's just no reason this need be.Mozillaguidelines to assure your C++ is portable.Note that one of Mozilla's software architectssays:
[Abelson and Sussman] is absolutely the best book on the topic I've ever seen. By the time you make it halfway through this book, you will have a very firm grasp on what object oriented programming is, because that's what this book is about — programming. This book uses Scheme as its instructional language, but please don't let that put you off. Because this book teaches you programming, not a particular language, and that's the point that so many mediocre programmers manage to get through school without understanding — that 'object oriented' is a style of programming, not a property of some particular language. This book is about problem solving techniques, not about figuring out where the semicolons go.
Java, while much better than C++, shares this same weakness:the smallest Java program requires about 12 keywords, each replete with meaning;a beginner must be told “put these words in your program in just this right order,else it won't work”.I've seen many students needlessly frustrated because it takes 30minto figure out their non-working program resulted from only inscribing eleven of the dozen necessary arcane glyphs.They may understand conceptually exactly what they want to do,but the arbitrary details of excessive syntax take out all the interest.(Some studies suggest that the prevalent teaching mode — encouragingarbitrary tinkering with little direction or meaningjust trying to get it to work — is one reason for the prounounced gender bias seen in the field of computer science.)
Any teacher knows not to distract from a topicby introducing advanced details to a beginner.Common sense? You wouldn't know it from all the peoplewho want to teach intro programming, but then use Java to do so.
For comparison, Java has 46 operators with 15 levels of precedence.
Indeed, any professional programmer who uses C++ willtell you that they use a disciplined subset of it,since without self-imposed guidelines it's easyto hang yourself with some of the language's “features”.You have to wonder, when style-guides for major, experience projects includesmany rules of the form “don't use feature X of the language”;it indicates that the community has learned what language features are more harmful than helpful.
联系客服