473,320 Members | 1,820 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,320 software developers and data experts.

Why C Is Not My Favourite Programming Language

I've been utilising C for lots of small and a few medium-sized personal
projects over the course of the past decade, and I've realised lately
just how little progress it's made since then. I've increasingly been
using scripting languages (especially Python and Bourne shell) which
offer the same speed and yet are far more simple and safe to use. I can
no longer understand why anyone would willingly use C to program
anything but the lowest of the low-level stuff. Even system utilities,
text editors and the like could be trivially written with no loss of
functionality or efficiency in Python. Anyway, here's my reasons. I'd
be interested to hear some intelligent advantages (not
rationalisations) for using C.

No string type
--------------

C has no string type. Huh? Most sane programming languages have a
string type which allows one to just say "this is a string" and let the
compiler take care of the rest. Not so with C. It's so stubborn and
dumb that it only has three types of variable; everything is either a
number, a bigger number, a pointer or a combination of those three.
Thus, we don't have proper strings but "arrays of unsigned integers".
"char" is basically just a really small number. And now we have to
start using unsigned ints to represent multibyte characters.

What. A. Crock. An ugly hack.

Functions for insignificant operations
--------------------------------------

Copying one string from another requires including <string.h> in your
source code, and there are two functions for copying a string. One
could even conceivably copy strings using other functions (if one
wanted to, though I can't imagine why). Why does any normal language
need two functions just for copying a string? Why can't we use the
assignment operator ('=') like for the other types? Oh, I forgot.
There's no such thing as strings in C; just a big continuous stick of
memory. Great! Better still, there's no syntax for:

* string concatenation
* string comparison
* substrings

Ditto for converting numbers to strings, or vice versa. You have to use
something like atol(), or strtod(), or a variant on printf(). Three
families of functions for variable type conversion. Hello? Flexible
casting? Hello?

And don't even get me started on the lack of an exponentiation
operator.

No string type: the redux
-------------------------

Because there's no real string type, we have two options: arrays or
pointers. Array sizes can only be constants. This means we run the risk
of buffer overflow since we have to try (in vain) to guess in advance
how many characters we need. Pathetic. The only alternative is to use
malloc(), which is just filled with pitfalls. The whole concept of
pointers is an accident waiting to happen. You can't free the same
pointer twice. You have to always check the return value of malloc()
and you mustn't cast it. There's no builtin way of telling if a spot of
memory is in use, or if a pointer's been freed, and so on and so forth.
Having to resort to low-level memory operations just to be able to
store a line of text is asking for...

The encouragement of buffer overflows
-------------------------------------

Buffer overflows abound in virtually any substantial piece of C code.
This is caused by programmers accidentally putting too much data in one
space or leaving a pointer pointing somewhere because a returning
function ballsed up somewhere along the line. C includes no way of
telling when the end of an array or allocated block of memory is
overrun. The only way of telling is to run, test, and wait for a
segfault. Or a spectacular crash. Or a slow, steady leakage of memory
from a program, agonisingly 'bleeding' it to death.

Functions which encourage buffer overflows
------------------------------------------

* gets()
* strcat()
* strcpy()
* sprintf()
* vsprintf()
* bcopy()
* scanf()
* fscanf()
* sscanf()
* getwd()
* getopt()
* realpath()
* getpass()

The list goes on and on and on. Need I say more? Well, yes I do.

You see, even if you're not writing any memory you can still access
memory you're not supposed to. C can't be bothered to keep track of the
ends of strings; the end of a string is indicated by a null '\0'
character. All fine, right? Well, some functions in your C library,
such as strlen(), perhaps, will just run off the end of a 'string' if
it doesn't have a null in it. What if you're using a binary string?
Careless programming this may be, but we all make mistakes and so the
language authors have to take some responsibility for being so
intolerant.

No builtin boolean type
-----------------------

If you don't believe me, just watch:

$ cat > test.c
int main(void)
{
bool b;
return 0;
}

$ gcc -ansi -pedantic -Wall -W test.c
test.c: In function 'main':
test.c:3: 'bool' undeclared (first use in this function)

Not until the 1999 ISO C standard were we finally able to use 'bool' as
a data type. But guess what? It's implemented as a macro and one
actually has to include a header file to be able to use it!

High-level or low-level?
------------------------

On the one hand, we have the fact that there is no string type and
little automatic memory management, implying a low-level language. On
the other hand, we have a mass of library functions, a preprocessor and
a plethora of other things which imply a high-level language. C tries
to be both, and as a result spreads itself too thinly.

The great thing about this is that when C is lacking a genuinely useful
feature, such as reasonably strong data typing, the excuse "C's a
low-level language" can always be used, functioning as a perfect
'reason' for C to remain unhelpfully and fatally sparse.

The original intention for C was for it to be a portable assembly
language for writing UNIX. Unfortunately, from its very inception C has
had extra things packed into it which make it fail as an assembly
language. Its kludgy strings are a good example. If it were at least
portable these failings might be forgivable, but C is not portable.

Integer overflow without warning
--------------------------------

Self explanatory. One minute you have a fifteen digit number, then try
to double or triple it and - boom - its value is suddenly
-234891234890892 or something similar. Stupid, stupid, stupid. How hard
would it have been to give a warning or overflow error or even just
reset the variable to zero?

This is widely known as bad practice. Most competent developers
acknowledge that silently ignoring an error is a bad attitude to have;
this is especially true for such a commonly used language as C.

Portability?!
-------------

Please. There are at least four official specifications of C I could
name from the top of my head and no compiler has properly implemented
all of them. They conflict, and they grow and grow. The problem isn't
subsiding; it's increasing each day. New compilers and libraries are
developed and proprietary extensions are being developed. GNU C isn't
the same as ANSI C isn't the same as K&R C isn't the same as Microsoft
C isn't the same as POSIX C. C isn't portable; all kinds of machine
architectures are totally different, and C can't properly adapt because
it's so muttonheaded. It's trapped in The Unix Paradigm.

If it weren't for the C preprocessor, then it would be virtually
impossible to get C to run on multiple families of processor hardware,
or even just slightly differing operating systems. A programming
language should not require a C preprocessor so that it can run on both
FreeBSD, Linux or Windows without failing to compile.

C is unable to adapt to new conditions for the sake of "backward
compatibility", throwing away the opportunity to get rid of stupid,
utterly useless and downright dangerous functions for a nonexistent
goal. And yet C is growing new tentacles and unnecessary features
because of idiots who think adding seven new functions to their C
library will make life easier. It does not.

Even the C89 and C99 standards conflict with each other in ridiculous
ways. Can you use the long long type or can't you? Is a certain
constant defined by a preprocessor macro hidden deep, deep inside my C
library? Is using a function in this particular way going to be
undefined, or acceptable? What do you mean, getch() isn't a proper
function but getc() and getchar() are?

The implications of this false 'portability'
--------------------------------------------

Because C pretends to be portable, even professional C programmers can
be caught out by hardware and an unforgiving programming language;
almost anything like comparisons, character assignments, arithmetic, or
string output can blow up spectacularly for no apparent reason because
of endianness or because your particular processor treats all chars as
unsigned or silly, subtle, deadly traps like that.

Archaic, unexplained conventions
--------------------------------

In addition to the aforementioned problems, C also has various
idiosyncracies (invariably unreported) which not even some teachers of
C are aware of:

* "Don't use fflush(stdin)."
* "gets() is evil."
* "main() must return an integer."
* "main() can only take one of three sets of arguments."
* "main() can only return either EXIT_SUCCESS or EXIT_FAILURE."
* "You musn't cast the return value of malloc()."
* "fileno() isn't an ANSI compliant function."
* "A preprocessor macro oughtn't use any of its arguments more than
once."

....all these unnecessary and unmentioned quirks mean buggy code. Death
by a thousand cuts. Ironic when you consider that Kernighan thinks of
Pascal in the same way when C has just as many little gotchas that
bleed you to death gradually and painfully.

Blaming The Progammer
---------------------

Due to the fact that C is pretty difficult to learn and even harder to
actually use without breaking something in a subtle yet horrific way
it's assumed that anything which goes wrong is the programmer's fault.
If your program segfaults, it's your fault. If it crashes, mysteriously
returning 184 with no error message, it's your fault. When one single
condition you'd just happened to have forgotten about whilst coding
screws up, it's your fault.

Obviously the programmer has to shoulder most of the responsibility for
a broken program. But as we've already seen, C positively tries to make
the programmer fail. This increases the failure rate and yet for some
reason we don't blame the language when yet another buffer overflow is
discovered. C programmers try to cover up C's inconsistencies and
inadequacies by creating a culture of 'tua culpa'; if something's
wrong, it's your fault, not that of the compiler, linker, assembler,
specification, documentation, or hardware.

Compilers have to take some of the blame. Two reasons. The first is
that most compilers have proprietary extensions built into them. Let me
remind you that half of the point of using C is that it should be
portable and compile anywhere. Adding extensions violates the original
spirit of C and removes one of its advantages (albeit an already
diminished advantage).

The other (and perhaps more pressing) reason is the lack of anything
beyond minimal error checking which C compilers do. For every ten types
of errors your compiler catches, another fifty will slip through.
Beyond variable type and syntax checking the compiler does not look for
anything else. All it can do is give warnings on unusual behaviour,
though these warnings are often spurious. On the other hand, a single
error can cause a ridiculous cascade, or make the compiler fall over
and die because of a misplaced semicolon, or, more accurately and
incriminatingly, a badly constructed parser and grammar. And yet,
despite this, it's your fault.

To quote The Unix Haters' Handbook:

"If you make even a small omission, like a single semicolon, a C
compiler tends to get so confused and annoyed that it bursts into tears
and complains that it just can't compile the rest of the file since one
missing semicolon has thrown it off so much."

So C compilers may well give literally hundreds of errors stating that
half of your code is wrong if you miss out a single semicolon. Can it
get worse? Of course it can! This is C!

You see, a compiler will often not deluge you with error information
when compiling. Sometimes it will give you no warning whatsoever even
if you write totally foolish code like this:

#include <stdio.h>

int main()
{
char *p;
puts(p);
return 0;
}

When we compile this with our 'trusty' compiler gcc, we get no errors
or warnings at all. Even when using the '-W' and '-Wall' flags to make
it watch out for dangerous code it says nothing.

$ gcc -W -Wall stupid.c
$

In fact, no warning is given ever unless you try to optimise the
program with a '-O' flag. But what if you never optimise your program?
Well, you now have a dangerous program. And unless you check the code
again you may well never notice that error.

What this section (and entire document) is really about is the sheer
unfriendliness of C and how it is as if it takes great pains to be as
difficult to use as possible. It is flexible in the wrong way; it can
do many, many different things, but this makes it impossible to do any
single thing with it.

Trapped in the 1970s
--------------------

C is over thirty years old, and it shows. It lacks features that modern
languages have such as exception handling, many useful data types,
function overloading, optional function arguments and garbage
collection. This is hardly surprising considering that it was
constructed from an assembler language with just one data type on a
computer from 1970.

C was designed for the computer and programmer of the 1970s,
sacrificing stability and programmer time for the sake of memory.
Despite the fact that the most recent standard is just half a decade
old, C has not been updated to take advantage of increased memory and
processor power to implement such things as automatic memory
management. What for? The illusion of backward compatibility and
portability.

Yet more missing data types
---------------------------

Hash tables. Why was this so difficult to implement? C is intended for
the programming of things like kernels and system utilities, which
frequently use hash tables. And yet it didn't occur to C's creators
that maybe including hash tables as a type of array might be a good
idea when writing UNIX? Perl has them. PHP has them. With C you have to
fake hash tables, and even then it doesn't really work at all.

Multidimensional arrays. Before you tell me that you can do stuff like
int multiarray[50][50][50] I think that I should point out that that's
an array of arrays of arrays. Different thing. Especially when you
consider that you can also use it as a bunch of pointers. C programmers
call this "flexibility". Others call it "redundancy", or, more
accurately, "mess".

Complex numbers. They may be in C99, but how many compilers support
that? It's not exactly difficult to get your head round the concept of
complex numbers, so why weren't they included in the first place? Were
complex numbers not discovered back in 1989?

Binary strings. It wouldn't have been that hard just to make a
compulsory struct with a mere two members: a char * for the string of
bytes and a size_t for the length of the string. Binary strings have
always been around on Unix, so why wasn't C more accommodating?

Library size
------------

The actual core of C is admirably small, even if some of the syntax
isn't the most efficient or readable (case in point: the combined '? :'
statement). One thing that is bloated is the C library. The number of
functions in a full C library which complies with all significant
standards runs into four digit figures. There's a great deal of
redundancy, and code which really shouldn't be there.

This has knock-on effects, such as the large number of configuration
constants which are defined by the preprocessor (which shouldn't be
necessary), the size of libraries (the GNU C library almost fills a
floppy disk and its documentation, three) and inconsistently named
groups of functions in addition to duplication.

For example, a function for converting a string to a long integer is
atol(). One can also use strtol() for exactly the same thing. Boom -
instant redundancy. Worse still, both functions are included in the
C99, POSIX and SUSv3 standards!

Can it get worse? Of course it can! This is C!

As a result it's only logical that there's an equivalent pair of atod()
and strtod() functions for converting a string to a double. As you've
probably guessed, this isn't true. They are called atof() and strtod().
This is very foolish. There are yet more examples scattered through the
standard C library like a dog's smelly surprises in a park.

The Single Unix Specification version three specifies 1,123 functions
which must be available to the C programmer of the compliant system. We
already know about the redundancies and unnecessary functions, but
across how many header files are these 1,123 functions spread out? 62.
That's right, on average a C library header will define approximately
eighteen functions. Even if you only need to use maybe one function
from each of, say, five libraries (a common occurrence) you may well
wind up including 90, 100 or even 150 function definitions you will
never need. Bloat, bloat, bloat. Python has the right idea; its import
statement allows you to define exactly the functions (and global
variables!) you need from each library if you prefer. But C? Oh, no.

Specifying structure members
----------------------------

Why does this need two operators? Why do I have to pick between '.' and
'->' for a ridiculous, arbitrary reason? Oh, I forgot; it's just yet
another of C's gotchas.

Limited syntax
--------------

A couple of examples should illustrate what I mean quite nicely. If
you've ever programmed in PHP for a substantial period of time, you're
probably aware of the 'break' keyword. You can use it to break out from
nested loops of arbitrary depth by using an integer, like so:

for ($i = 0; $i < 10; $i++) {

for ($j = 0; $j < 10; $j++) {

for ($k = 0; $k < 10; $k++) {
break 2;
}
}

/* breaks out to here */

}

There is no way of doing this in C. If you want to break out from a
series of nested for or while loops then you have to use a goto. This
is what is known as a crude hack.

In addition to this, there is no way to compare any non-numerical data
type using a switch statement. Not even strings. In the programming
language D, one can do:

char s[];

switch (s) {

case "hello":
/* something */
break;

case "goodbye":
/* something else */
break;

case "maybe":
/* another action */
break;

default:
/* something */
break;

}

C does not allow you to use switch and case statements for strings. One
must use several variables to iterate through an array of case strings
and compare them to the given string with strcmp(). This reduces
performance and is just yet another hack.

In fact, this is an example of gratuitous library functions running
wild once again. Even comparing one string to another requires use of
the strcmp() function:

char string[] = "Blah, blah, blah\n";

if (strcmp(string, "something") == 0) {

/* do something */

}

Flushing standard I/O
---------------------

A simple microcosm of the "you can do this, but not that" philosophy of
C; one has to do two different things to flush standard input and
standard output.

To flush the standard output stream, the fflush() function is used
(defined by <stdio.h>). One doesn't usually need to do this after every
bit of text is printed, but it's nice to know it's there, right?

Unfortunately, fflush() can't be used to flush the contents of standard
input. Some C standards explicitly define it as having undefined
behaviour, but this is so illogical that even textbook authors
sometimes mistakenly use fflush(stdin) in examples and some compilers
won't bother to warn you about it. One shouldn't even have to flush
standard input; you ask for a character with getchar(), and the program
should just read in the first character given and disregard the rest.
But I digress...

There is no 'real' way to flush standard input up to, say, the end of a
line. Instead one has to use a kludge like so:

int c;

do {

errno = 0;
c = getchar();

if (errno) {
fprintf(stderr,
"Error flushing standard input buffer: %s\n",
strerror(errno));
}

} while ((c != '\n') && (!feof(stdin)));

That's right; you need to use a variable, a looping construct, two
library functions and several lines of exception handling code to flush
the standard
input buffer.

Inconsistent error handling
---------------------------

A seasoned C programmer will be able to tell what I'm talking about
just by reading the title of this section. There are many incompatible
ways in which a C library function indicates that an error has
occurred:

* Returning zero.
* Returning nonzero.
* Returning EOF.
* Returning a NULL pointer.
* Setting errno.
* Requiring a call to another function.
* Outputting a diagnostic message to the user.
* Triggering an assertion failure.
* Crashing.

Some functions may actually use up to three of these methods. (For
instance, fread().) But the thing is that none of these are compatible
with each other and error handling does not occur automatically; every
time a C programmer uses a library function they must check manually
for an error. This bloats code which would otherwise be perfectly
readable without if-blocks for error handling and variables to keep
track of errors. In a large software project one must write a section
of code for error handling hundreds of times. If you forget, something
can go horribly wrong. For example, if you don't check the return value
of malloc() you may accidentally try to use a null pointer. Oops...

Commutative array subscripting
------------------------------

"Hey, Thompson, how can I make C's syntax even more obfuscated and
difficult to understand?"

"How about you allow 5[var] to mean the same as var[5]?"

"Wow; unnecessary and confusing syntactic idiocy! Thanks!"

"You're welcome, Dennis."

Yes, I understand that array subscription is just a form of addition
and so it should be commutative, but doesn't it seem just a bit foolish
to say that 5[var] is the same as var[5]? How on earth do you take the
var'th value of 5?

Variadic anonymous macros
-------------------------

In case you don't understand what variadic anonymous macros are,
they're macros (i.e. pseudofunctions defined by the preprocessor) which
can take a variable number of arguments. Sounds like a simple thing to
implement. I mean, it's all done by the preprocessor, right? And
besides, you can define proper functions with variable numbers of
arguments even in the original K&R C, right?

In that case, why can't I do:

#define error(...) fprintf(stderr, ...)

without getting a warning from GCC?

warning: anonymous variadic macros were introduced in C99

That's right, folks. Not until late 1999, 30 years after development on
the C programming language began, have we been allowed to do such a
simple task with the preprocessor.

The C standards don't make sense
--------------------------------

Only one simple quote from the ANSI C standard - nay, a single footnote
- is needed to demonstrate the immense idiocy of the whole thing.
Ladies, gentlemen, and everyone else, I present to you...footnote 82:

All whitespace is equivalent except in certain situations.

I'd make a cutting remark about this, but it'd be too easy.

Too much preprocessor power
---------------------------

Rather foolishly, half of the actual C language is reimplemented in the
preprocessor. (This should be a concern from the start; redundancy
usually indicates an underlying problem.) We can #define fake
variables, fake conditions with #ifdef and #ifndef, and look, there's
even #if, #endif and the rest of the crew! How useful!

Erm, sorry, no.

Preprocessors are a good idea for a language like C. As has been
iterated, C is not portable. Preprocessors are vital to bridging the
gap between different computer architectures and libraries and allowing
a program to compile on multiple machines without having to rely on
external programs. The #define statement, in this case, can be used
perfectly validly to set 'flags' that can be used by a program to
determine all sorts of things: which C standard is being used, which
library, who wrote it, and so on and so forth.

Now, the situation isn't as bad as for C++. In C++, the preprocessor is
so packed with unnecessary rubbish that one can actually use it to
calculate an arbitrary series of Fibonacci numbers at compile-time.
However, C comes dangerously close; it allows the programmer to define
fake global variables with wacky values which would not otherwise be
proper code, and then compare values of these variables. Why? It's not
needed; the C language of the Plan 9 operating system doesn't let you
play around with preprocessor definitions like this. It's all just
bloat.

"But what about when we want to use a constant throughout a program? We
don't want to have to go through the program changing the value each
time we want to change the constant!" some may complain. Well, there's
these things called global variables. And there's this keyword, const.
It makes a constant variable. Do you see where I'm going with this?

You can do search and replace without the preprocessor, too. In fact,
they were able to do it back in the seventies on the very first
versions of Unix. They called it sed. Need something more like cpp? Use
m4 and stop complaining. It's the Unix way.

Nov 14 '05 #1
134 7832

evolnet.regu...@gmail.com wrote:
I've been utilising C for lots of small and a few medium-sized personal projects over the course of the past decade, and I've realised lately
just how little progress it's made since then. I've increasingly been
using scripting languages (especially Python and Bourne shell) which
offer the same speed and yet are far more simple and safe to use. I can no longer understand why anyone would willingly use C to program
anything but the lowest of the low-level stuff. Even system utilities, text editors and the like could be trivially written with no loss of
functionality or efficiency in Python. Anyway, here's my reasons. I'd
be interested to hear some intelligent advantages (not
rationalisations) for using C.


So your scripted programs offer the same speed as C programs? Wow,
those interpreters for your languages (most likely written in C) are
really good these days. Or maybe the credit falls with the OS/kernel
code (most likely written in C). Or maybe it's because you're C
programming skills are so horrible that it borders the inefficiency of
scripted languages.

I bet around 99% of all CPUs/MPUs have C compilers (or cross compilers)
that can target them (no other language is even close to that %). If
only those system implementers had read your post before, we might not
have this mess.

Nov 14 '05 #2
Question #1:
WHY DID YOU POST THIS?

If you want to be babied, fine, go through life just pointing and
grunting at things. All I see is a bunch of pathetic excuses that
explains your inability to program in C. Shell-scripts are as fast as
C? What is wrong with you! Why is power bad! Why do people still
program in assembly?
C++ is better? OOP might be good for somethings like GUI, but for
anything else it's overkill.
If you are unable to tough it up and accept your incompetence, fine,
don't post here and complain!

Nov 14 '05 #3
I'm not asking to be "babied", but I'd like a language with as much
"power" and "functionality" as C that isn't as prone to crashing
constantly.

Nov 14 '05 #4
ev*************@gmail.com wrote:

I'm not asking to be "babied", but I'd like a language with as much
"power" and "functionality" as C that isn't as prone to crashing
constantly.


Then learn how to write C programs *properly*.
Nov 14 '05 #5

"Steven" <si*******@yahoo.com> wrote

If you want to be babied, fine, go through life just pointing and
grunting at things. All I see is a bunch of pathetic excuses that
explains your inability to program in C. Shell-scripts are as fast as
C? What is wrong with you! Why is power bad! Why do people still
program in assembly?
C++ is better? OOP might be good for somethings like GUI, but for
anything else it's overkill.
If you are unable to tough it up and accept your incompetence, fine,
don't post here and complain!

The C language does have faults, some genuine ones which were mentioned,
like the 2D array problem.
Many other faults weren't mentioned. For instance one of the worst mistakes
K and R made was to use the same identifier for a "character" and a "byte",
presumably because their character-mapped displays needed pokeing to squeeze
out decent performance. Now we're stuck with no easy way to move from ASCII.

However most of the post was criticising C for not being a large, high-level
language with things like built in string types. A typical processor has no
instructions for manipulating strings directly. So to provide such
facilities as part of the language proper would mean that a C program could
no longer be translated directly to assembly.

I use C a lot, partly because it is so efficient (but much easier and more
portable than assembler), partly because it is small and therefore you spend
you time getting the program written rather than playing with language
features, and partly because, being so useful, it is widely available so you
can knock up a C routine without having to wonder how you install your Perl
interpreter / Java virtual machine / C++ standard template library on your
particular machine.
Nov 14 '05 #6
Malcolm wrote:

Many other faults weren't mentioned. For instance one of the worst mistakes
K and R made was to use the same identifier for a "character" and a "byte",
What has K to do with this?
presumably because their character-mapped displays needed pokeing to squeeze
out decent performance. Now we're stuck with no easy way to move from ASCII.


I suspect that I'm not the only clc subscriber to have used C on
non-ASCII systems and have had no problems in this regard.
Nov 14 '05 #7
I would consider your arguments more seriously if you bothered to make
them seem objective. As it is, you just sound like you're whining.
Also, after reading the entire post, it's obvious that your list of
complaints is very short:

1) You want a string type
2) You don't like low level programming
3) You don't think C is portable

Come to think of it, those all sound like opinions rather than hard
facts. If you don't like C, don't use it. Nobody is forcing you. If you
don't want anyone else to use C, tough. It's impossible to use your own
opinions to change the opinions of others.

Nov 14 '05 #8
In article <11*********************@c13g2000cwb.googlegroups. com>,
<ev*************@gmail.com> wrote:
I'm not asking to be "babied", but I'd like a language with as much
"power" and "functionality" as C that isn't as prone to crashing
constantly.


It is not the language that is prone to crashing constantly, if anything
is crashing it is your program. The solution is to write better programs.
Blaming ones own lack of skills on the tools are not productive.

--
Göran Larsson http://www.mitt-eget.com/
Nov 14 '05 #9
On 5 Feb 2005 14:59:46 -0800, ev*************@gmail.com wrote in
comp.lang.c:
I'm not asking to be "babied", but I'd like a language with as much
"power" and "functionality" as C that isn't as prone to crashing
constantly.


Then feel free to write one. Other people have. But take your
whining someplace else. If you have sincere proposals for changes to
C, you're in the wrong group. Try comp.std.c. If you just want to
complain, start a blog.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.contrib.andrew.cmu.edu/~a...FAQ-acllc.html
Nov 14 '05 #10
ev*************@gmail.com wrote:

I'm not asking to be "babied", but I'd like a language with as much
"power" and "functionality" as C that isn't as prone to crashing
constantly.


Ada and Pascal come to mind. (when properly implemented and meeting
standards). Many of the C problems arise from maintaining
compatibility, just as the pentia/AMDs have maintained 8088/6
compatibility. The cumulative software is worth considerably more
than the hardware.

--
"If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers." - Keith Thompson
Nov 14 '05 #11
ev*************@gmail.com wrote:

I'm not asking to be "babied", but I'd like a language with as much
"power" and "functionality" as C that isn't as prone to crashing
constantly.


I use:

C - for device drivers, low level library code.
Python - for small scripts.
O'caml - for large complex stuff that that the others
aren't good at.

I haven't done much handyman type stuff recently, but when
I do I use spanners, screwdrivers and hammers for whatever
those tools do best.

If you want to write in a high level language with
sophisticated features, that compiles to fast native
binaries and is also cross platform (*nix, win32 and
MacOSX), take a look at:

http://www.ocaml.org/

Erik
--
+-----------------------------------------------------------+
Erik de Castro Lopo no****@mega-nerd.com (Yes it's valid)
+-----------------------------------------------------------+
"I could never learn to use C++, because of the completely overwhelming
desire to redesign the language every time I tried to use it, but this
is the normal, healthy reaction to C++." -- Erik Naggum
Nov 14 '05 #12
In article <11**********************@z14g2000cwz.googlegroups .com>,
<ev*************@gmail.com> wrote:
:Yet more missing data types
:Complex numbers. They may be in C99, but how many compilers support
:that? It's not exactly difficult to get your head round the concept of
:complex numbers, so why weren't they included in the first place? Were
:complex numbers not discovered back in 1989?

I've worked in scientific programming for 20 years, including
spending years cleaning code that had been written by tens of
untrained programmers over the 20 years before that.

In that 20 years, the number of times that we've needed complex
numbers was... complex(0.0,0.0).

Seriously. there wasn't a need for them after 1st year university
courses.

I'm not saying that we never used formulae that involved complex
entities, but we rarely use them -as- complex numbers. Most of the
time our programs just treat them as multi-dimensional vectors... and
we use a couple of thousand dimensions in our vectors, so there is
nothing special, as far as our algorithms go, about 2 dimensions.
For us it'd be more important to do multiply-and-add operations
on arbitrarily high dimensional vectors. I must have missed the part
of your message where you railed against C not having that feature.
After all APL had it back in 1969, so why isn't it a ksh primitive?
:One thing that is bloated is the C library. The number of
:functions in a full C library which complies with all significant
:standards runs into four digit figures. There's a great deal of
:redundancy, and code which really shouldn't be there.

And the number of modules in Python 2.4's Global Module Index is 362.
If I didn't lose count, 97 of those are marked as non-portable.
This is progress, that 1/4 of your core modules are non-portable ??

The Python Package Index (pypi.org) has another 759 modules in it.
Speaking of scripting languages: Perl's CPAN has some 7500 modules
in it. Did Python "do it right" and the other 6750 modules in CPAN
are just 9 different variants on what Python does inherently? Or
is it just the case that successful languages attract large bodies
of useful libraries, and that it is considered worthwhile to
standardize the best of these to avoid having to re-invent the wheel?
:Why does this need two operators? Why do I have to pick between '.' and
:'->' for a ridiculous, arbitrary reason? Oh, I forgot; it's just yet
:another of C's gotchas.

There were two really big success stories in instruction
set architectures in the 1960's: The IBM 360 series and the DEC PDP
architecture. Both offered a number of different addressing modes,
with the PDP perhaps a bit cleaner. The PDP architecture ideals
begat the Motorola 6800, 6809, and 680x0 series, which were market
leaders in their own times. [Quite lot of Z80 and 8086 and 80x86 chips
got sold too, but everything after the 8080 was an ugly grafting
of wart upon wart, which by now has gotten so bad that the Pentium
had to be implimented as a RISC chip internally.] Anyhow, I cannot
think of -any- successful CPU architecture that offered just one
addressing mode [e.g., that all operations accept move to and from
memory were register-to-register only, with all pointer handling
done by loading the base pointer and doing arithmetic operations upon it.]
Why then should we expect that there is only one memory accessor
operator in a programming language?
:Unfortunately, fflush() can't be used to flush the contents of standard
:input.

What exactly does "flushing the contents of standard input" *mean*
when standard input might be from a terminal, a pipe, a socket,
a fifo, a pty, a mmap'd shared memory segment, a tape drive,
a file, a raw disk block, or other arcane possibilities -- each
of which might or might not be in binary mode, and each of which
might or might not be record-oriented instead of stream oriented?
:Yes, I understand that array subscription is just a form of addition
:and so it should be commutative, but doesn't it seem just a bit foolish
:to say that 5[var] is the same as var[5]? How on earth do you take the
:var'th value of 5?

But it's not foolish that in ksh if you refer to an array name
without a subscript then the reference is taken as being to element 0
of the array, rather than to the array as a collection?
--
Entropy is the logarithm of probability -- Boltzmann
Nov 14 '05 #13
Walter Roberson wrote:

I've worked in scientific programming for 20 years, including
spending years cleaning code that had been written by tens of
untrained programmers over the 20 years before that.

In that 20 years, the number of times that we've needed complex
numbers was... complex(0.0,0.0).

Seriously. there wasn't a need for them after 1st year university
courses.


I do a lot of programming of Digitial Signal Processing code
and therefore use complex numbers all the time. Even C99's
complex numbers are insufficient which forces me to use C++
for this code instead even though I otherwise dislike C++
immensely.

Erik
--
+-----------------------------------------------------------+
Erik de Castro Lopo no****@mega-nerd.com (Yes it's valid)
+-----------------------------------------------------------+
"The object-oriented model makes it easy to build up programs by
accretion. What this often means, in practice, is that it provides
a structured way to write spaghetti code." -- Paul Graham
Nov 14 '05 #14
Luke Wu wrote:
[ snipped ]
I bet around 99% of all CPUs/MPUs have C compilers (or cross compilers)
that can target them (no other language is even close to that %). If ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Forth.
only those system implementers had read your post before, we might not
have this mess.

--
Julian V. Noble
Professor Emeritus of Physics
jv*@lessspamformother.virginia.edu
^^^^^^^^^^^^^^^^^^
http://galileo.phys.virginia.edu/~jvn/

"For there was never yet philosopher that could endure the
toothache patiently."

-- Wm. Shakespeare, Much Ado about Nothing. Act v. Sc. 1.
Nov 14 '05 #15
ev*************@gmail.com wrote:
I'm not asking to be "babied", but I'd like a language with as much
"power" and "functionality" as C that isn't as prone to crashing
constantly.


Huh?

1. A language doesn't crash. Your program does.

2. If your program crashes, there is something wrong with it.

3. If you can't use a hammer without crushing your fingers, maybe
you shouldn't be nailing at all.

4. Last but not least, I actually think "crashes" are good. They
make us see we made a mistake. Any engineer with some sort of ethics
wants to be able to see his errors so he can correct them. Of course,
most of the "crashing" should occur while testing. Not after the
product has shipped.

5. Testing is good.

6. Education-wise, I think the right step is to go from a very simple
language (like Basic), then to Pascal to learn procedural programming
the right way, then to C, when one is ready. A lot of older programmers
have followed this path (for historical reasons) and they are some of
the best programmers out there. I, for example, haven't started studying
C until my Master's degree. I already had developed a lot of Pascal
applications before. It helped tremendously.

7. Nobody's perfect, but I wouldn't trust a programmer that couldn't
write a single middle-sized program in C that was robust enough never to
crash at all. To me, that's a good way of evaluating their sense of
rigor.

8. If you really don't like C, I suggest Ada.

9. Remember there are millions of ways bugs can manifest themselves.
Like I said, crashes are often the "nicest" way. The worst is
definitely when you think everything is going right, whereas your
program is a total wreck inside. Even in case of a safety device, I'd
rather see one device "crash", immediately backed up by a redundant
device that could see something went wrong in a timely manner - instead
of the device running bogus code forever, leading to a disaster.

10. I, and many of us, have learnt many languages besides C. I've been
using C for over 12 years, in all kind of settings and areas. And it's
still my favorite language. Go figure.

11. Go to 1. ;-)
Nov 14 '05 #16
It's all well and good saying this, but if the language itself is
packed with booby traps and requires every element of the entire body
of code to be meticulously planned out to avoid bugs, it's inevitable
that no large program in the language will avoid introducing at least
one bug.

Nov 14 '05 #17
ev*************@gmail.com wrote:
I've been utilising C for lots of small and a few medium-sized personal
projects over the course of the past decade, and I've realised lately
just how little progress it's made since then. I've increasingly been
using scripting languages (especially Python and Bourne shell) which
offer the same speed and yet are far more simple and safe to use. I can
no longer understand why anyone would willingly use C to program
anything but the lowest of the low-level stuff. Even system utilities,
text editors and the like could be trivially written with no loss of
functionality or efficiency in Python. Anyway, here's my reasons. I'd
be interested to hear some intelligent advantages (not
rationalisations) for using C.

[snip long long rant-like thing]


This is all (except the opening paragraph) taken from
http://www.kuro5hin.org/story/2004/2/7/144019/8872

The OP copied the whole thing and pretended it was his reasons.

--
Eric Schmidt
Nov 14 '05 #18
In article <11*********************@f14g2000cwb.googlegroups. com>,
<ev*************@gmail.com> wrote:
:It's all well and good saying this, but if the language itself is
:packed with booby traps and requires every element of the entire body
:of code to be meticulously planned out to avoid bugs, it's inevitable
:that no large program in the language will avoid introducing at least
:one bug.

I don't recall hearing that people had gotten very far with
automated proof of correctness in *any* Turing-equivilent
programming language. Proofs have a way of exploding badly
with even very small programs, due to branch points -- each
branch point potentially doubles the size of the proof,
and loops can imply indefinite branching.

Consider for example, the amount of effort needed to prove
the correctness of these few lines:

while ( md5(x) != 0 ) x = md5(x);

Thus it is pretty much inevitable that large programs in *any*
useful programming language will have at least one bug. Even in
very highly refined and constrained languages that are built as
academic projects in programming and metaprogramming to avoid bugs.
--
Is "meme" descriptive or perscriptive? Does the knowledge that
memes exist not subtly encourage the creation of more memes?
-- A Child's Garden Of Memes
Nov 14 '05 #19

Eric Schmidt wrote:
ev*************@gmail.com wrote:
I've been utilising C for lots of small and a few medium-sized personal projects over the course of the past decade, and I've realised lately just how little progress it's made since then. I've increasingly been using scripting languages (especially Python and Bourne shell) which offer the same speed and yet are far more simple and safe to use. I can no longer understand why anyone would willingly use C to program
anything but the lowest of the low-level stuff. Even system utilities, text editors and the like could be trivially written with no loss of functionality or efficiency in Python. Anyway, here's my reasons. I'd be interested to hear some intelligent advantages (not
rationalisations) for using C.
>
> [snip long long rant-like thing]


This is all (except the opening paragraph) taken from
http://www.kuro5hin.org/story/2004/2/7/144019/8872

The OP copied the whole thing and pretended it was his reasons.

--
Eric Schmidt


If you are the real Eric Schmidt, please get your developers to fix up
google groups' treatment of leading blank spaces in usenet posts.

Nov 14 '05 #20
ev*************@gmail.com wrote:

<snip>


If you would like a string_t type built into the language,
comp.std.c is where you should be *discussing* this.
Whining like you have will not solve your problems. This
problem may also have been discussed in the past, so search
old posts and gain more understanding about the problems
the standardizing committee faces when adding, removing
or modifying features. Compatibility with the *huge* amount
of source code that has already been written comes to mind
almost instantly. Oh, and here `huge` is really *huge*.
I wish I could stress it more than my news client allows.
You cannot simply wake up some day and say, "Let there be
a better string type" and have a string type appear from nowhere.
God didn't have to be compatible with "Humans Version -1."

C, like any other language, has flaws. This is why new languages
come up almost everyday. If you want "safe" programming, please
look at Java or some other popular language. As Dan Pop himself put,
"C is quirky, flawed, and an enormous success." It couldn't be more
true. C is what it was meant to be.

The fact that you're complaining about the language only shows
that you like C and you would like it to develop into something
you would like it to be. So, why whine? comp.std.c is where you
should go.

Remember, C is a sharp blade in the *right* hands and if you don't
handle the blade properly, you risk the danger of injuring yourself
and others. If you don't like C, choose another language that
suits your taste. Stop complaining about C strings, however.
You can give http://bstring.sourceforge.net/ a look.
Nothing is perfect.

Regards,
Jonathan.

--
Email: "jonathan [period] burd [commercial-at] gmail [period] com" sans-WSP

"We must do something. This is something. Therefore, we must do this."
- Keith Thompson
Nov 14 '05 #21
Jonathan Burd wrote:

C, like any other language, has flaws. This is why new languages
come up almost everyday. If you want "safe" programming, please
look at Java or some other popular language. As Dan Pop himself put,
"C is quirky, flawed, and an enormous success." It couldn't be more
true. C is what it was meant to be.
Actually, it wasn't The Great Dan Pop who first said that. It was
just some guy called Dennis Ritchie.
"We must do something. This is something. Therefore, we must do this."
- Keith Thompson


Actually, this one was from Jonathan Lynn & Antony Jay, not Keith
Thompson.

It was used in the "Party Games" episode of "Yes Minister".
Nov 14 '05 #22
infobahn wrote:
Jonathan Burd wrote:
C, like any other language, has flaws. This is why new languages
come up almost everyday. If you want "safe" programming, please
look at Java or some other popular language. As Dan Pop himself put,
"C is quirky, flawed, and an enormous success." It couldn't be more
true. C is what it was meant to be.

Actually, it wasn't The Great Dan Pop who first said that. It was
just some guy called Dennis Ritchie.

"We must do something. This is something. Therefore, we must do this."
- Keith Thompson

Actually, this one was from Jonathan Lynn & Antony Jay, not Keith
Thompson.

It was used in the "Party Games" episode of "Yes Minister".


Actually, I must have been mistaken about the quotes. Actually, thanks
for correcting me. :)

Regards,
Jonathan.

--
Email: "jonathan [period] burd [commercial-at] gmail [period] com" sans-WSP

"We must do something. This is something. Therefore, we must do this."
- Keith Thompson
Nov 14 '05 #23
Off topic; please stop reading now.

infobahn <in******@btinternet.com> writes:
Jonathan Burd wrote:

[...]
"We must do something. This is something. Therefore, we must do this."
- Keith Thompson


Actually, this one was from Jonathan Lynn & Antony Jay, not Keith
Thompson.

It was used in the "Party Games" episode of "Yes Minister".


Really? I've been using that as my sig quote for about the last 9
months. I honestly don't know where I got it, or whether I invented
it independently. I don't think I've ever seen an episode of "Yes
Minister".

Most Google hits for the quotation are occurrences of my sig quote;
when I filter those out there are still a few dozen hits, some
referring to it as the "politician's syllogism".

Possibly the writer of that episode got it from somewhere else.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 14 '05 #24

"infobahn" <in******@btinternet.com> wrote

I suspect that I'm not the only clc subscriber to have used C on
non-ASCII systems and have had no problems in this regard.

How would you make strlen() return the length of a Unicode string on a
system where bytes are naturally 8 bits?
Nov 14 '05 #25
Keith Thompson wrote:
infobahn <in******@btinternet.com> writes:
Jonathan Burd wrote:

[...]
"We must do something. This is something. Therefore, we must
do this." - Keith Thompson


Actually, this one was from Jonathan Lynn & Antony Jay, not Keith
Thompson.

It was used in the "Party Games" episode of "Yes Minister".


Really? I've been using that as my sig quote for about the last
9 months. I honestly don't know where I got it, or whether I
invented it independently. I don't think I've ever seen an
episode of "Yes Minister".

Most Google hits for the quotation are occurrences of my sig
quote; when I filter those out there are still a few dozen hits,
some referring to it as the "politician's syllogism".

Possibly the writer of that episode got it from somewhere else.


Obviously you have polluted the data base. "Yes, Minister" was a
very funny right-pondian effort seen on PBS in left-pondia some
years ago.

--
"If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers." - Keith Thompson
Nov 14 '05 #26
On 02/05/05 23:15, ev*************@gmail.com wrote:
I've been utilising C for lots of small and a few medium-sized personal
projects over the course of the past decade, and I've realised lately
just how little progress it's made since then. I've increasingly been
.............


Probably you never wrote code for an embedded system. Or never go thru
the about one million lines of code of a telephon switching system.

Ciao
Giovanni
--
A computer is like an air conditioner,
it stops working when you open Windows.
Registered Linux user #337974 <http://counter.li.org/>

Nov 14 '05 #27
Malcolm wrote:

"infobahn" <in******@btinternet.com> wrote

I suspect that I'm not the only clc subscriber to have used C on
non-ASCII systems and have had no problems in this regard.

How would you make strlen() return the length of a Unicode string on a
system where bytes are naturally 8 bits?


That's a very different question. :-) If you meant "supporting a
character set other than the one directly offered by the
implementation", then I agree it's another matter entirely.
Nov 14 '05 #28
CBFalconer wrote:

Keith Thompson wrote:

Possibly the writer of that episode got it from somewhere else.


Obviously you have polluted the data base. "Yes, Minister" was a
very funny right-pondian effort seen on PBS in left-pondia some
years ago.


Furthermore, the episode in question pre-dates net.lang.c, never
mind comp.lang.c.
Nov 14 '05 #29
On 5 Feb 2005 14:15:37 -0800, in comp.lang.c , ev*************@gmail.com
wrote:
I've been utilising C for lots of small and a few medium-sized personal
projects over the course of the past decade, and I've realised lately
just how little progress it's made since then. I've increasingly been
using scripting languages (especially Python and Bourne shell)
Good. In that case, go post your comments in python and unix groups. This
group is to discuss using C, not to discuss why you're not using it.
C has no string type. Huh? Most sane programming languages have a
string type which allows one to just say "this is a string"
C++ is thataway --->
Functions for insignificant operations
Ask yourself how C++ copies a string.
The encouragement of buffer overflows
This remark can only be made by a non-C programmer.
Functions which encourage buffer overflows
and which any actual C programmer knows to avoid and/or treat with care.
* bcopy()
* getwd()
* getopt()
* realpath()
* getpass()
and these ones aren't even C functions.
No builtin boolean type
Wrong. check out stdbool.h
If you don't believe me, just watch: .....test.c:3: 'bool' undeclared (first use in this function)
So, try using the right type. Thats simply a fatuous mistake.
Integer overflow without warning
--------------------------------

Self explanatory. One minute you have a fifteen digit number, then try
to double or triple it and - boom - its value is suddenly
-234891234890892 or something similar. Stupid, stupid, stupid.
Yeah, of the programmer.
How hard
would it have been to give a warning or overflow error or even just
reset the variable to zero?
If its so easy, you do it. Remember your solution has to work on anything
from a DSP to a Cray, via a Vax and an 8086.
Please. There are at least four official specifications of C I could
name from the top of my head and no compiler has properly implemented
all of them. They conflict, and they grow and grow.
And this differs from any other programming language.... how?
Archaic, unexplained conventions
such as using good progamming practice.
Blaming The Progammer
when he screws up, who else to blame?
C is over thirty years old,
Apart from the revision in 1999 of course. C++ meanwhile is how old? And
bourne shell is, er, over thirty, and python is.... what was your point
exactly?
It lacks features that modern
languages have such as exception handling, many useful data types,
function overloading, optional function arguments and garbage
collection.


Ignoring the fact that much of this is useless on many of C's target
architectures, I again wonder how this differs from other languages. BTW
don't bullshit anyone here, we mostly programme in all of them, you'll be
caught.
--
Mark McIntyre
CLC FAQ <http://www.eskimo.com/~scs/C-faq/top.html>
CLC readme: <http://www.ungerhu.com/jxh/clc.welcome.txt>
Nov 14 '05 #30
On 5 Feb 2005 19:28:27 -0800, in comp.lang.c , ev*************@gmail.com
wrote:
It's all well and good saying this, but if the language itself is
packed with booby traps
Its not, its just that you're incompetent at it. Sorry, but if you think
your statement to be true, then it is the only remaining conclusion.
and requires every element of the entire body
of code to be meticulously planned out to avoid bugs,
It doesn't, any more than any othe language does./
it's inevitable
that no large program in the language will avoid introducing at least
one bug.


This is true of ANY programme in any language. Its an axiom.

--
Mark McIntyre
CLC FAQ <http://www.eskimo.com/~scs/C-faq/top.html>
CLC readme: <http://www.ungerhu.com/jxh/clc.welcome.txt>
Nov 14 '05 #31
In article <IB********@approve.se>, Goran Larsson <ho*@invalid.invalid> wrote:
In article <11*********************@c13g2000cwb.googlegroups. com>,
<ev*************@gmail.com> wrote:
I'm not asking to be "babied", but I'd like a language with as much
"power" and "functionality" as C that isn't as prone to crashing
constantly.


It is not the language that is prone to crashing constantly, if anything
is crashing it is your program. The solution is to write better programs.
Blaming ones own lack of skills on the tools are not productive.


"It is a poor workman that blames his tools". Yes, as true now as ever.

Having said that, the only sense in which the OP's obvious trolling is at
all worthwhile is by taking it from a manager's perspective (that is, not
from a programmer's perspective).

While it is certainly true that it is a poor workman who blames his tools,
it *is* legitimate to criticize the tools chosen by and used by OTHER
PEOPLE, especially if you are paying the salaries of those OTHER PEOPLE.

So, I invite you all to continue this discussion from that perspective.

Nov 14 '05 #32

Walter Roberson wrote:
In article <11*********************@f14g2000cwb.googlegroups. com>,
<ev*************@gmail.com> wrote:
:It's all well and good saying this, but if the language itself is
:packed with booby traps and requires every element of the entire body :of code to be meticulously planned out to avoid bugs, it's inevitable :that no large program in the language will avoid introducing at least :one bug.

I don't recall hearing that people had gotten very far with
automated proof of correctness in *any* Turing-equivilent
programming language. Proofs have a way of exploding badly
with even very small programs, due to branch points -- each
branch point potentially doubles the size of the proof,
and loops can imply indefinite branching.

Consider for example, the amount of effort needed to prove
the correctness of these few lines:

while ( md5(x) != 0 ) x = md5(x);

Thus it is pretty much inevitable that large programs in *any*
useful programming language will have at least one bug. Even in
very highly refined and constrained languages that are built as
academic projects in programming and metaprogramming to avoid bugs.
--
Is "meme" descriptive or perscriptive? Does the knowledge that
memes exist not subtly encourage the creation of more memes?
-- A Child's Garden Of Memes


True, but my point is:

(1) C introduces entirely new classes of bugs
and
(2) C makes bugs more likely, regardless of the programmer's skill
and
(3) C makes it much harder to root out and fix bugs

and I still haven't seen any reasoning against this.

Nov 14 '05 #33
In that case, why is it that there are so many buffer overflows in so
many C programs written by presumably experienced coders and yet so few
in programs written in *any other language*?

Nov 14 '05 #34
ev*************@gmail.com scribbled the following
on comp.lang.c:
In that case, why is it that there are so many buffer overflows in so
many C programs written by presumably experienced coders and yet so few
in programs written in *any other language*?


I find it hard to believe there are more buffer overflows in C programs
than there are in assembly programs. Unless you don't count assembly as
a language.

--
/-- Joona Palaste (pa*****@cc.helsinki.fi) ------------- Finland --------\
\-------------------------------------------------------- rules! --------/
"It was, er, quite bookish."
- Horace Boothroyd
Nov 14 '05 #35
There are fewer buffer overflows in assembly programs because people
don't overuse assembly language as they do C.

Nov 14 '05 #36
ev*************@gmail.com wrote:
There are fewer buffer overflows in assembly programs because people
don't overuse assembly language as they do C.


We are talking proportions here! The percentage remains the same
regardless of the sample size! A simple understanding of mathematics
will probably be good for you!

Assembly language is pure power, the only reason people don't use it
often is because the portability and *difficulty* of the language. But
if speed is called for, like a arbitrary-precision library, what
language is used for the core routines? Assembly. If you are too
babish to learn to use the power, fine, get a Mac program in Java!!

Give anyone power and it can be misused. C assumes the programmer is
*COMPETENT*, and therefore C tries not to provide too much overhead and
sometimes unneccessary processes in the program. You are responsible
for how the program runs, checking the bounds, checking for errors,
etc, not the compiler. The compiler does exactly what you tell it to
do without trying to outsmart you. That is about as close you can get
to machine language without assembly. If you're not smarter than the
compiler at trying to control your program, you're better off not
programming.

Booby traps? Like those nonexistant (or at least rarely used)
functions (where did you find those functions, and why do you even use
them)? Power and efficency itself is a booby trap. Who said writing
in C should be easy, it is not called a mid-level programming language
for nothing.

If you think something is hard, don't learn it and don't complain.
Just because you are lacking in intelletual aptitude doesn't mean none
of us have the intelletual aptitude program in C either.

Power or simplicity comes at a price. Look at Java: huge library, OOP,
garbage-collection, exception-checking, portability, etc. All nice and
dandy. But what happened to its flexibility? What happened to its
speed? Can you do *ANY* low level manipulation? What happens when you
what a low-level routine? It not so simple anymore, is it? You can't
even easily do a conditional compilation. Even C++ has big flaws, how
many memory leaks have you seen in a well written C program!

I am still puzzled by your post. What did you expect to accomplish?
Attract attention to yourself? Make us feel sorry for you
incompetence? Tell the world about you inability to accept power?
Nothing is free in life, and POWER COMES AT A COST!!

Nov 14 '05 #37
ev*************@gmail.com wrote:
Walter Roberson wrote:

.... snip ...

Thus it is pretty much inevitable that large programs in *any*
useful programming language will have at least one bug. Even in
very highly refined and constrained languages that are built as
academic projects in programming and metaprogramming to avoid bugs.


True, but my point is:

(1) C introduces entirely new classes of bugs and
(2) C makes bugs more likely, regardless of the programmer's
skill and
(3) C makes it much harder to root out and fix bugs

and I still haven't seen any reasoning against this.


Please do snip what you quote, especially sig lines.

C is no worse in these respects than assembly language, except when
it tries to ape higher level languages and do things behind your
back. A case in point is the hidden arithmetic promotions.

So it is well to think of C as a portable structured assembly
language with an extensive library. That way you probably won't
get hurt, unless you do something foolish like using unsigned bit
fields and expecting them to act unsigned.

--
"If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers." - Keith Thompson
Nov 14 '05 #38
ev*************@gmail.com wrote:

In that case, why is it that there are so many buffer overflows in
so many C programs written by presumably experienced coders and yet
so few in programs written in *any other language*?


For the same reasons that most automobile accidents have a
teen-ager at the heart of it. Teen-ager implies novice. Today
that teenager gets a copy of "Dummies Learn C in 28 minutes", or
some other BullSchildt, together with a whiz bang IDE, and
laboriously create a "Hello World" that occupies 0.25 megabytes
[1]. They now cackle fatuosly and go to work for General Crap
Software. Some of them in this very newsgroup even claim to work
for NASA and jpl.

[1] While in the days of CP/M a "Hello World" could be about 25
bytes. It need not be appreciably larger today.

--
"If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers." - Keith Thompson
Nov 14 '05 #39
>"infobahn" <in******@btinternet.com> wrote
I suspect that I'm not the only clc subscriber to have used C on
non-ASCII systems and have had no problems in this regard.

In article <cu**********@newsg3.svr.pol.co.uk>
Malcolm <ma*****@55bank.freeserve.co.uk> wrote:How would you make strlen() return the length of a Unicode string on a
system where bytes are naturally 8 bits?


It already does. It returns the length in (C) bytes (units of
"char"). The fact that it takes up to 4 C bytes to encode a single
display position is another matter entirely; and if you want columns
to line up, you need something more than "number of display positions"
anyway, because Unicode fonts are (at least mostly) proportional.

(I suspect, however, that infobahn was referring to EBCDIC on
IBM mainframes. C works fine there, although plain char must be
unsigned, because, e.g., '0' == 0xf0, and CHAR_BIT is still 8.
EBCDIC does break a lot of programs that assume 'I'+1 == 'J',
though.)
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Nov 14 '05 #40
In article <11*********************@o13g2000cwo.googlegroups. com>,
Steven <si*******@yahoo.com> wrote:
:Power or simplicity comes at a price. Look at Java: huge library, OOP,
:garbage-collection, exception-checking, portability, etc. All nice and
:dandy. But what happened to its flexibility? What happened to its
:speed? Can you do *ANY* low level manipulation? What happens when you
:what a low-level routine? It not so simple anymore, is it? You can't
:even easily do a conditional compilation.

We had a programming team here who put in several person years of
efforts into writing their scientific programs in Java, thinking that
the OOP facilities together with the strong type checking and
prevention of array and buffer overflows would help them to produce
good and useful code. They also took care to use the "self-documenting"
style to embed documentation in the code, and they took code metrics
an so on -- in other words, the project had definite elements of
"software engineering" rather than just a bunch of people throwing
code together.

The project in that form was given up after roughly three years.
They reclaimed a bunch of the APIs they had developed [the OOP was
certainly not a complete waste], but they are now rewriting in
pure C++ (with perhaps the occasional C module.) Even with the most
advanced JIT compilers they could find, and using all the Java tricks
they could think of, they simply couldn't get enough speed in
the portions of the code that needed to extract portions of
multidimensional arrays for processing. No pointers in Java,
remember, and no pointer arithmetic, so there were no opportunities
to take advantage of any knowledge of in-memory layout of their
multidimensional arrays: at each step they had to create
a new vector of the proper length, loop copying the data into the
vector, and pass the vector in to the work routine. With datasets
starting at 1/2 Gb and destined to get much larger, the memory moves
were killing their efficiency completely, and there was -no-
way in Java around it.

Strongly typed langauges with semi-opaque data structures that
exist to enforce "correct code" and hide differences such as
the '.' operator vs the -> operator, usually sooner or later get
into the way when there is massive of work to be done.

[The only reason I say 'usually' rather than 'always' is that
it would not be impossible to define a higher level language
that offered "handles" by reference into multidimensional
data, that did subscript checking and yet knew how to efficently
map "vector" accesses into hidden pointer arithmetic to get at
the real data.]
--
'ignorandus (Latin): "deserving not to be known"'
-- Journal of Self-Referentialism
Nov 14 '05 #41
CBFalconer wrote:
ev*************@gmail.com wrote:
In that case, why is it that there are so many buffer overflows in
so many C programs written by presumably experienced coders and yet
so few in programs written in *any other language*?

For the same reasons that most automobile accidents have a
teen-ager at the heart of it. Teen-ager implies novice. Today
that teenager gets a copy of "Dummies Learn C in 28 minutes", or
some other BullSchildt, together with a whiz bang IDE, and
laboriously create a "Hello World" that occupies 0.25 megabytes
[1]. They now cackle fatuosly and go to work for General Crap
Software. Some of them in this very newsgroup even claim to work
for NASA and jpl.

[1] While in the days of CP/M a "Hello World" could be about 25
bytes. It need not be appreciably larger today.


Darn, I made it never below 1/2K (including standard startup and cleanup
code)...

-Michael
--
E-Mail: Mine is an /at/ gmx /dot/ de address.
Nov 14 '05 #42
In article <11*********************@o13g2000cwo.googlegroups. com>,
<ev*************@gmail.com> wrote:

:True, but my point is:

:(1) C introduces entirely new classes of bugs
:and
:(2) C makes bugs more likely, regardless of the programmer's skill
:and
:(3) C makes it much harder to root out and fix bugs

:and I still haven't seen any reasoning against this.

Introduced relative to -what- ? Do I get to compare it against
the other languages that were available at the time of it's
development in 1969-1973, such as:

- numerous assemblers
- Fortran 66, Fortran G, Fortran H
- The original Pascal (1970)
- PL/1 (1969)
- Algol 68
- APL (1969)
- LISP, LISP 1.5, MacLISP
--
Is "meme" descriptive or perscriptive? Does the knowledge that
memes exist not subtly encourage the creation of more memes?
-- A Child's Garden Of Memes
Nov 14 '05 #43

"Chris Torek" <no****@torek.net> wrote
Malcolm <ma*****@55bank.freeserve.co.uk> wrote:
How would you make strlen() return the length of a Unicode string on a
system where bytes are naturally 8 bits?
It already does. It returns the length in (C) bytes (units of
"char"). The fact that it takes up to 4 C bytes to encode a single
display position is another matter entirely; and if you want columns
to line up, you need something more than "number of display positions"
anyway, because Unicode fonts are (at least mostly) proportional.

You can do it by declaring char to be 32 bits. But now we have this problem.
I want a program that opens an image file, does something fancy with the
data, and writes an output. Filenames are composed of characters and
obviously I want my Chinese customers to be able to load and save files in
their own language. So four bit chars are reasonable.

Now the bulk of the program consists of

void imageroutine(unsigned char *rgb, int width, int height)
{
}
Bytes are 8 bits, whilst pixels are naturally 24 bits with 8 bits for each
pixel. So I want to take advantage of this to access my pixels one component
at a time. But I can't.

The best way round is probably to pass in pixels as 32 bits and waste the
top 8. Often this will also increase performance.

But now we have further difficulties. Let's say I typedef unsigned long as
"colour" and macros RED GREEN and BLUE to access the channels. Now we've
polluted the symbol space. It becomes that bit much more difficult to hook
my imageroutine into different programs, because there is no natural layout
of the pixels in memory.

Now my friend has produced a JPEG loader. He faced the same problem. So he
typedefed unsigned long as "color" and macros RED GREEN AND BLUE, but using
Microsoft format (blues in the low bit).

Then of course most machines come with 8 or at a pinch 9 bit bytes. However
it is entirely plausible that people will start using "long" as a longer
type than int, ie 64 bits. Wasting half the space for an image-processing
routine is probably not acceptable. So we could easily end up doing a
rewrite.

See the sort of problems you very quickly run into?
(I suspect, however, that infobahn was referring to EBCDIC on
IBM mainframes. C works fine there, although plain char must be
unsigned, because, e.g., '0' == 0xf0, and CHAR_BIT is still 8.
EBCDIC does break a lot of programs that assume 'I'+1 == 'J',
though.)

The other progams that break are those that read and write from file formats
that contain ASCII strings. For instance an IFF file contains 4 byte ASCII
mnemonic chunk ids. It is extremely tempting to write

if(!memcmp(chunk, "DATA", 4))

rather than coding the bytes numerically, but it will break on EBCDIC.
Nov 14 '05 #44
Yes we understand, ... It is quitte difficult to get your hands on
good programming books when you are visualy impaired.

However there are enough options for you. A good start-point would be.
The National Library Service for the Blind
http://lcweb.loc.gov/nls

If you decide afterall that C programming is just not your thing you
could also try singing. There are Nr. of blind people who have been
known to make a very good living out of it. Ray Charles, Stevie
Wonder.. Etc..

http://www.stevie-wonder.com/

Peace bro & Good Luck...

Lucy..

p.s.
don't forget to send us some of your C code when you located your
computer again.. That would be great..!!

On 5 Feb 2005 14:15:37 -0800, ev*************@gmail.com wrote:
I've been utilising C for lots of small and a few medium-sized personal
projects over the course of the past decade, and I've realised lately
just how little progress it's made since then. I've increasingly been
using scripting languages (especially Python and Bourne shell) which
offer the same speed and yet are far more simple and safe to use. I can
no longer understand why anyone would willingly use C to program
anything but the lowest of the low-level stuff. Even system utilities,
text editors and the like could be trivially written with no loss of
functionality or efficiency in Python. Anyway, here's my reasons. I'd
be interested to hear some intelligent advantages (not
rationalisations) for using C.

No string type
--------------

C has no string type. Huh? Most sane programming languages have a
string type which allows one to just say "this is a string" and let the
compiler take care of the rest. Not so with C. It's so stubborn and
dumb that it only has three types of variable; everything is either a
number, a bigger number, a pointer or a combination of those three.
Thus, we don't have proper strings but "arrays of unsigned integers".
"char" is basically just a really small number. And now we have to
start using unsigned ints to represent multibyte characters.

What. A. Crock. An ugly hack.

Functions for insignificant operations
--------------------------------------

Copying one string from another requires including <string.h> in your
source code, and there are two functions for copying a string. One
could even conceivably copy strings using other functions (if one
wanted to, though I can't imagine why). Why does any normal language
need two functions just for copying a string? Why can't we use the
assignment operator ('=') like for the other types? Oh, I forgot.
There's no such thing as strings in C; just a big continuous stick of
memory. Great! Better still, there's no syntax for:

* string concatenation
* string comparison
* substrings

Ditto for converting numbers to strings, or vice versa. You have to use
something like atol(), or strtod(), or a variant on printf(). Three
families of functions for variable type conversion. Hello? Flexible
casting? Hello?

And don't even get me started on the lack of an exponentiation
operator.

No string type: the redux
-------------------------

Because there's no real string type, we have two options: arrays or
pointers. Array sizes can only be constants. This means we run the risk
of buffer overflow since we have to try (in vain) to guess in advance
how many characters we need. Pathetic. The only alternative is to use
malloc(), which is just filled with pitfalls. The whole concept of
pointers is an accident waiting to happen. You can't free the same
pointer twice. You have to always check the return value of malloc()
and you mustn't cast it. There's no builtin way of telling if a spot of
memory is in use, or if a pointer's been freed, and so on and so forth.
Having to resort to low-level memory operations just to be able to
store a line of text is asking for...

The encouragement of buffer overflows
-------------------------------------

Buffer overflows abound in virtually any substantial piece of C code.
This is caused by programmers accidentally putting too much data in one
space or leaving a pointer pointing somewhere because a returning
function ballsed up somewhere along the line. C includes no way of
telling when the end of an array or allocated block of memory is
overrun. The only way of telling is to run, test, and wait for a
segfault. Or a spectacular crash. Or a slow, steady leakage of memory
from a program, agonisingly 'bleeding' it to death.

Functions which encourage buffer overflows
------------------------------------------

* gets()
* strcat()
* strcpy()
* sprintf()
* vsprintf()
* bcopy()
* scanf()
* fscanf()
* sscanf()
* getwd()
* getopt()
* realpath()
* getpass()

The list goes on and on and on. Need I say more? Well, yes I do.

You see, even if you're not writing any memory you can still access
memory you're not supposed to. C can't be bothered to keep track of the
ends of strings; the end of a string is indicated by a null '\0'
character. All fine, right? Well, some functions in your C library,
such as strlen(), perhaps, will just run off the end of a 'string' if
it doesn't have a null in it. What if you're using a binary string?
Careless programming this may be, but we all make mistakes and so the
language authors have to take some responsibility for being so
intolerant.

No builtin boolean type
-----------------------

If you don't believe me, just watch:

$ cat > test.c
int main(void)
{
bool b;
return 0;
}

$ gcc -ansi -pedantic -Wall -W test.c
test.c: In function 'main':
test.c:3: 'bool' undeclared (first use in this function)

Not until the 1999 ISO C standard were we finally able to use 'bool' as
a data type. But guess what? It's implemented as a macro and one
actually has to include a header file to be able to use it!

High-level or low-level?
------------------------

On the one hand, we have the fact that there is no string type and
little automatic memory management, implying a low-level language. On
the other hand, we have a mass of library functions, a preprocessor and
a plethora of other things which imply a high-level language. C tries
to be both, and as a result spreads itself too thinly.

The great thing about this is that when C is lacking a genuinely useful
feature, such as reasonably strong data typing, the excuse "C's a
low-level language" can always be used, functioning as a perfect
'reason' for C to remain unhelpfully and fatally sparse.

The original intention for C was for it to be a portable assembly
language for writing UNIX. Unfortunately, from its very inception C has
had extra things packed into it which make it fail as an assembly
language. Its kludgy strings are a good example. If it were at least
portable these failings might be forgivable, but C is not portable.

Integer overflow without warning
--------------------------------

Self explanatory. One minute you have a fifteen digit number, then try
to double or triple it and - boom - its value is suddenly
-234891234890892 or something similar. Stupid, stupid, stupid. How hard
would it have been to give a warning or overflow error or even just
reset the variable to zero?

This is widely known as bad practice. Most competent developers
acknowledge that silently ignoring an error is a bad attitude to have;
this is especially true for such a commonly used language as C.

Portability?!
-------------

Please. There are at least four official specifications of C I could
name from the top of my head and no compiler has properly implemented
all of them. They conflict, and they grow and grow. The problem isn't
subsiding; it's increasing each day. New compilers and libraries are
developed and proprietary extensions are being developed. GNU C isn't
the same as ANSI C isn't the same as K&R C isn't the same as Microsoft
C isn't the same as POSIX C. C isn't portable; all kinds of machine
architectures are totally different, and C can't properly adapt because
it's so muttonheaded. It's trapped in The Unix Paradigm.

If it weren't for the C preprocessor, then it would be virtually
impossible to get C to run on multiple families of processor hardware,
or even just slightly differing operating systems. A programming
language should not require a C preprocessor so that it can run on both
FreeBSD, Linux or Windows without failing to compile.

C is unable to adapt to new conditions for the sake of "backward
compatibility", throwing away the opportunity to get rid of stupid,
utterly useless and downright dangerous functions for a nonexistent
goal. And yet C is growing new tentacles and unnecessary features
because of idiots who think adding seven new functions to their C
library will make life easier. It does not.

Even the C89 and C99 standards conflict with each other in ridiculous
ways. Can you use the long long type or can't you? Is a certain
constant defined by a preprocessor macro hidden deep, deep inside my C
library? Is using a function in this particular way going to be
undefined, or acceptable? What do you mean, getch() isn't a proper
function but getc() and getchar() are?

The implications of this false 'portability'
--------------------------------------------

Because C pretends to be portable, even professional C programmers can
be caught out by hardware and an unforgiving programming language;
almost anything like comparisons, character assignments, arithmetic, or
string output can blow up spectacularly for no apparent reason because
of endianness or because your particular processor treats all chars as
unsigned or silly, subtle, deadly traps like that.

Archaic, unexplained conventions
--------------------------------

In addition to the aforementioned problems, C also has various
idiosyncracies (invariably unreported) which not even some teachers of
C are aware of:

* "Don't use fflush(stdin)."
* "gets() is evil."
* "main() must return an integer."
* "main() can only take one of three sets of arguments."
* "main() can only return either EXIT_SUCCESS or EXIT_FAILURE."
* "You musn't cast the return value of malloc()."
* "fileno() isn't an ANSI compliant function."
* "A preprocessor macro oughtn't use any of its arguments more than
once."

...all these unnecessary and unmentioned quirks mean buggy code. Death
by a thousand cuts. Ironic when you consider that Kernighan thinks of
Pascal in the same way when C has just as many little gotchas that
bleed you to death gradually and painfully.

Blaming The Progammer
---------------------

Due to the fact that C is pretty difficult to learn and even harder to
actually use without breaking something in a subtle yet horrific way
it's assumed that anything which goes wrong is the programmer's fault.
If your program segfaults, it's your fault. If it crashes, mysteriously
returning 184 with no error message, it's your fault. When one single
condition you'd just happened to have forgotten about whilst coding
screws up, it's your fault.

Obviously the programmer has to shoulder most of the responsibility for
a broken program. But as we've already seen, C positively tries to make
the programmer fail. This increases the failure rate and yet for some
reason we don't blame the language when yet another buffer overflow is
discovered. C programmers try to cover up C's inconsistencies and
inadequacies by creating a culture of 'tua culpa'; if something's
wrong, it's your fault, not that of the compiler, linker, assembler,
specification, documentation, or hardware.

Compilers have to take some of the blame. Two reasons. The first is
that most compilers have proprietary extensions built into them. Let me
remind you that half of the point of using C is that it should be
portable and compile anywhere. Adding extensions violates the original
spirit of C and removes one of its advantages (albeit an already
diminished advantage).

The other (and perhaps more pressing) reason is the lack of anything
beyond minimal error checking which C compilers do. For every ten types
of errors your compiler catches, another fifty will slip through.
Beyond variable type and syntax checking the compiler does not look for
anything else. All it can do is give warnings on unusual behaviour,
though these warnings are often spurious. On the other hand, a single
error can cause a ridiculous cascade, or make the compiler fall over
and die because of a misplaced semicolon, or, more accurately and
incriminatingly, a badly constructed parser and grammar. And yet,
despite this, it's your fault.

To quote The Unix Haters' Handbook:

"If you make even a small omission, like a single semicolon, a C
compiler tends to get so confused and annoyed that it bursts into tears
and complains that it just can't compile the rest of the file since one
missing semicolon has thrown it off so much."

So C compilers may well give literally hundreds of errors stating that
half of your code is wrong if you miss out a single semicolon. Can it
get worse? Of course it can! This is C!

You see, a compiler will often not deluge you with error information
when compiling. Sometimes it will give you no warning whatsoever even
if you write totally foolish code like this:

#include <stdio.h>

int main()
{
char *p;
puts(p);
return 0;
}

When we compile this with our 'trusty' compiler gcc, we get no errors
or warnings at all. Even when using the '-W' and '-Wall' flags to make
it watch out for dangerous code it says nothing.

$ gcc -W -Wall stupid.c
$

In fact, no warning is given ever unless you try to optimise the
program with a '-O' flag. But what if you never optimise your program?
Well, you now have a dangerous program. And unless you check the code
again you may well never notice that error.

What this section (and entire document) is really about is the sheer
unfriendliness of C and how it is as if it takes great pains to be as
difficult to use as possible. It is flexible in the wrong way; it can
do many, many different things, but this makes it impossible to do any
single thing with it.

Trapped in the 1970s
--------------------

C is over thirty years old, and it shows. It lacks features that modern
languages have such as exception handling, many useful data types,
function overloading, optional function arguments and garbage
collection. This is hardly surprising considering that it was
constructed from an assembler language with just one data type on a
computer from 1970.

C was designed for the computer and programmer of the 1970s,
sacrificing stability and programmer time for the sake of memory.
Despite the fact that the most recent standard is just half a decade
old, C has not been updated to take advantage of increased memory and
processor power to implement such things as automatic memory
management. What for? The illusion of backward compatibility and
portability.

Yet more missing data types
---------------------------

Hash tables. Why was this so difficult to implement? C is intended for
the programming of things like kernels and system utilities, which
frequently use hash tables. And yet it didn't occur to C's creators
that maybe including hash tables as a type of array might be a good
idea when writing UNIX? Perl has them. PHP has them. With C you have to
fake hash tables, and even then it doesn't really work at all.

Multidimensional arrays. Before you tell me that you can do stuff like
int multiarray[50][50][50] I think that I should point out that that's
an array of arrays of arrays. Different thing. Especially when you
consider that you can also use it as a bunch of pointers. C programmers
call this "flexibility". Others call it "redundancy", or, more
accurately, "mess".

Complex numbers. They may be in C99, but how many compilers support
that? It's not exactly difficult to get your head round the concept of
complex numbers, so why weren't they included in the first place? Were
complex numbers not discovered back in 1989?

Binary strings. It wouldn't have been that hard just to make a
compulsory struct with a mere two members: a char * for the string of
bytes and a size_t for the length of the string. Binary strings have
always been around on Unix, so why wasn't C more accommodating?

Library size
------------

The actual core of C is admirably small, even if some of the syntax
isn't the most efficient or readable (case in point: the combined '? :'
statement). One thing that is bloated is the C library. The number of
functions in a full C library which complies with all significant
standards runs into four digit figures. There's a great deal of
redundancy, and code which really shouldn't be there.

This has knock-on effects, such as the large number of configuration
constants which are defined by the preprocessor (which shouldn't be
necessary), the size of libraries (the GNU C library almost fills a
floppy disk and its documentation, three) and inconsistently named
groups of functions in addition to duplication.

For example, a function for converting a string to a long integer is
atol(). One can also use strtol() for exactly the same thing. Boom -
instant redundancy. Worse still, both functions are included in the
C99, POSIX and SUSv3 standards!

Can it get worse? Of course it can! This is C!

As a result it's only logical that there's an equivalent pair of atod()
and strtod() functions for converting a string to a double. As you've
probably guessed, this isn't true. They are called atof() and strtod().
This is very foolish. There are yet more examples scattered through the
standard C library like a dog's smelly surprises in a park.

The Single Unix Specification version three specifies 1,123 functions
which must be available to the C programmer of the compliant system. We
already know about the redundancies and unnecessary functions, but
across how many header files are these 1,123 functions spread out? 62.
That's right, on average a C library header will define approximately
eighteen functions. Even if you only need to use maybe one function
from each of, say, five libraries (a common occurrence) you may well
wind up including 90, 100 or even 150 function definitions you will
never need. Bloat, bloat, bloat. Python has the right idea; its import
statement allows you to define exactly the functions (and global
variables!) you need from each library if you prefer. But C? Oh, no.

Specifying structure members
----------------------------

Why does this need two operators? Why do I have to pick between '.' and
'->' for a ridiculous, arbitrary reason? Oh, I forgot; it's just yet
another of C's gotchas.

Limited syntax
--------------

A couple of examples should illustrate what I mean quite nicely. If
you've ever programmed in PHP for a substantial period of time, you're
probably aware of the 'break' keyword. You can use it to break out from
nested loops of arbitrary depth by using an integer, like so:

for ($i = 0; $i < 10; $i++) {

for ($j = 0; $j < 10; $j++) {

for ($k = 0; $k < 10; $k++) {
break 2;
}
}

/* breaks out to here */

}

There is no way of doing this in C. If you want to break out from a
series of nested for or while loops then you have to use a goto. This
is what is known as a crude hack.

In addition to this, there is no way to compare any non-numerical data
type using a switch statement. Not even strings. In the programming
language D, one can do:

char s[];

switch (s) {

case "hello":
/* something */
break;

case "goodbye":
/* something else */
break;

case "maybe":
/* another action */
break;

default:
/* something */
break;

}

C does not allow you to use switch and case statements for strings. One
must use several variables to iterate through an array of case strings
and compare them to the given string with strcmp(). This reduces
performance and is just yet another hack.

In fact, this is an example of gratuitous library functions running
wild once again. Even comparing one string to another requires use of
the strcmp() function:

char string[] = "Blah, blah, blah\n";

if (strcmp(string, "something") == 0) {

/* do something */

}

Flushing standard I/O
---------------------

A simple microcosm of the "you can do this, but not that" philosophy of
C; one has to do two different things to flush standard input and
standard output.

To flush the standard output stream, the fflush() function is used
(defined by <stdio.h>). One doesn't usually need to do this after every
bit of text is printed, but it's nice to know it's there, right?

Unfortunately, fflush() can't be used to flush the contents of standard
input. Some C standards explicitly define it as having undefined
behaviour, but this is so illogical that even textbook authors
sometimes mistakenly use fflush(stdin) in examples and some compilers
won't bother to warn you about it. One shouldn't even have to flush
standard input; you ask for a character with getchar(), and the program
should just read in the first character given and disregard the rest.
But I digress...

There is no 'real' way to flush standard input up to, say, the end of a
line. Instead one has to use a kludge like so:

int c;

do {

errno = 0;
c = getchar();

if (errno) {
fprintf(stderr,
"Error flushing standard input buffer: %s\n",
strerror(errno));
}

} while ((c != '\n') && (!feof(stdin)));

That's right; you need to use a variable, a looping construct, two
library functions and several lines of exception handling code to flush
the standard
input buffer.

Inconsistent error handling
---------------------------

A seasoned C programmer will be able to tell what I'm talking about
just by reading the title of this section. There are many incompatible
ways in which a C library function indicates that an error has
occurred:

* Returning zero.
* Returning nonzero.
* Returning EOF.
* Returning a NULL pointer.
* Setting errno.
* Requiring a call to another function.
* Outputting a diagnostic message to the user.
* Triggering an assertion failure.
* Crashing.

Some functions may actually use up to three of these methods. (For
instance, fread().) But the thing is that none of these are compatible
with each other and error handling does not occur automatically; every
time a C programmer uses a library function they must check manually
for an error. This bloats code which would otherwise be perfectly
readable without if-blocks for error handling and variables to keep
track of errors. In a large software project one must write a section
of code for error handling hundreds of times. If you forget, something
can go horribly wrong. For example, if you don't check the return value
of malloc() you may accidentally try to use a null pointer. Oops...

Commutative array subscripting
------------------------------

"Hey, Thompson, how can I make C's syntax even more obfuscated and
difficult to understand?"

"How about you allow 5[var] to mean the same as var[5]?"

"Wow; unnecessary and confusing syntactic idiocy! Thanks!"

"You're welcome, Dennis."

Yes, I understand that array subscription is just a form of addition
and so it should be commutative, but doesn't it seem just a bit foolish
to say that 5[var] is the same as var[5]? How on earth do you take the
var'th value of 5?

Variadic anonymous macros
-------------------------

In case you don't understand what variadic anonymous macros are,
they're macros (i.e. pseudofunctions defined by the preprocessor) which
can take a variable number of arguments. Sounds like a simple thing to
implement. I mean, it's all done by the preprocessor, right? And
besides, you can define proper functions with variable numbers of
arguments even in the original K&R C, right?

In that case, why can't I do:

#define error(...) fprintf(stderr, ...)

without getting a warning from GCC?

warning: anonymous variadic macros were introduced in C99

That's right, folks. Not until late 1999, 30 years after development on
the C programming language began, have we been allowed to do such a
simple task with the preprocessor.

The C standards don't make sense
--------------------------------

Only one simple quote from the ANSI C standard - nay, a single footnote
- is needed to demonstrate the immense idiocy of the whole thing.
Ladies, gentlemen, and everyone else, I present to you...footnote 82:

All whitespace is equivalent except in certain situations.

I'd make a cutting remark about this, but it'd be too easy.

Too much preprocessor power
---------------------------

Rather foolishly, half of the actual C language is reimplemented in the
preprocessor. (This should be a concern from the start; redundancy
usually indicates an underlying problem.) We can #define fake
variables, fake conditions with #ifdef and #ifndef, and look, there's
even #if, #endif and the rest of the crew! How useful!

Erm, sorry, no.

Preprocessors are a good idea for a language like C. As has been
iterated, C is not portable. Preprocessors are vital to bridging the
gap between different computer architectures and libraries and allowing
a program to compile on multiple machines without having to rely on
external programs. The #define statement, in this case, can be used
perfectly validly to set 'flags' that can be used by a program to
determine all sorts of things: which C standard is being used, which
library, who wrote it, and so on and so forth.

Now, the situation isn't as bad as for C++. In C++, the preprocessor is
so packed with unnecessary rubbish that one can actually use it to
calculate an arbitrary series of Fibonacci numbers at compile-time.
However, C comes dangerously close; it allows the programmer to define
fake global variables with wacky values which would not otherwise be
proper code, and then compare values of these variables. Why? It's not
needed; the C language of the Plan 9 operating system doesn't let you
play around with preprocessor definitions like this. It's all just
bloat.

"But what about when we want to use a constant throughout a program? We
don't want to have to go through the program changing the value each
time we want to change the constant!" some may complain. Well, there's
these things called global variables. And there's this keyword, const.
It makes a constant variable. Do you see where I'm going with this?

You can do search and replace without the preprocessor, too. In fact,
they were able to do it back in the seventies on the very first
versions of Unix. They called it sed. Need something more like cpp? Use
m4 and stop complaining. It's the Unix way.


Nov 14 '05 #45
In article <11********************@g14g2000cwa.googlegroups.c om>,
ev*************@gmail.com says...
In that case, why is it that there are so many buffer overflows in so
many C programs written by presumably experienced coders


There lies the flaw -- "presumably experienced".

--
Randy Howard (2reply remove FOOBAR)
"Making it hard to do stupid things often makes it hard
to do smart ones too." -- Andrew Koenig
Nov 14 '05 #46

Walter Roberson wrote:
In article <11*********************@o13g2000cwo.googlegroups. com>,
<ev*************@gmail.com> wrote:

:True, but my point is:

:(1) C introduces entirely new classes of bugs
:and
:(2) C makes bugs more likely, regardless of the programmer's skill
:and
:(3) C makes it much harder to root out and fix bugs

:and I still haven't seen any reasoning against this.

Introduced relative to -what- ? Do I get to compare it against
the other languages that were available at the time of it's
development in 1969-1973, such as:

- numerous assemblers
- Fortran 66, Fortran G, Fortran H
- The original Pascal (1970)
- PL/1 (1969)
- Algol 68
- APL (1969)
- LISP, LISP 1.5, MacLIS


Yes. Don't forget to compare it to all of the other, superior languages
that have been created subsequently, too!

Nov 14 '05 #47
> Darn, I made it never below 1/2K (including standard startup and
cleanup
code)...

I got it down to 25 bytes (A86).

Nov 14 '05 #48
> Darn, I made it never below 1/2K (including standard startup and
cleanup
code)...

I got it down to 25 bytes (A86).

Nov 14 '05 #49
I got "hello world!" down to exactly 25 bytes. (A86 assembly)

Nov 14 '05 #50

This thread has been closed and replies have been disabled. Please start a new discussion.

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.