Martin Brown said:
The most obvious way is not always the most efficient algorithm. Certain C constructs are hell for optimising
compilers.
Absolutely. But I believe it is important to have the choice. I can choose to
write C code quickly but it might not be efficient, or I can choose spend
more time and write highly optimised code. I'm not forced down a
particular route by the language designer. And that freedom is why many
of us prefer C.
And without using lint (or a similar tool) there are far too many gotchas from typos possible. A well known classic
one being (and variants thereof):
if (x=OK) {
do something
}
It is virtually certain that the author meant (x==OK) but provided that the value of OK is non-zero the condition is
always satisfied.
Just about every C compiler gives a warning for this (which can often be
configured to be reported as an error), no need to use lint.
They do improve overall productivity though since a wild pointer or array indexing error is trapped imediately before
it can do signifcant damage. Defence in depth is the maxim for high reliability code. It may not be as exciting as a
high wire act without safety nets.
Terminating a program is damaging as well if it happens for real.
The first you know about wild pointers or improperly terminated arrays in Windows is when some hacker takes control of
root priviledges on your machine.
These are typically basic mistakes when reading input data without adding
the correct checks. You always have to assume the data might be manipulated
or corrupted.
Strongly typed languages that force you to write clearly what you intend have the effect of removing a lot of
ambiguity. In embedded systems this can have advantages. The code may be somewhat more verbose as a result, but it is
more amenable to static testing tools as a result.
Having to think about the problem can be an advantage indeed. But it is also
a disadvantage if you just want to do some prototyping or want to make design
changes at a later date. For example you can easily change a structure into a
union in C, while in Pascal it requires major changes.
Automatic runtime checks during development are a powerful productivity aid. The sooner a program is faulted for an
error the better. Manually adding debugging assertions improperly can have side effects that only show up in the
production build. This is particularly true in a mixed ability team of programmers.
The goal is to add explicit checks that make all automatic checks completely
redundant. One typically enables all checks for debug and testing but a subset
in the release build. So you get faster development using the extra checks but
don't pay the runtime cost of checks that are not strictly required in the release.
And that is why Windows Vista is such a perfect bullet proof robust operating system that will run for months on end
without crashing. Pull the other one it has got bells on. Most of the MS security defects are caused by various buffer
overrun defects in C/C++ code.
You are quite right, Vista is indeed a very robust OS that runs for months without
crashing. I've use it on a daily basis for the past 18 months and it is at least as
reliable as XP (not a single crash despite uptimes of many months). Have you
even used Vista yourself? I guess bashing Vista is still a popular pastime.
Wilco