Talk:Criticism of the C programming language

Latest comment: 16 years ago by DAGwyn in topic Tools for mitigating issues with C

Restoring Neutral Point Of View edit

Some of the additions were more carping about C than factual. For example, there are solid reasons why we don't want truncated source files to go undetected, and no compelling reason I have ever heard to the contrary; further, most well-defined programming languages have a similar requirement, so even if you don't like the property it is not really a criticism of C. This article was split off the main C programming language article for structural reasons, not to provide a forum for airing grievances about C. I made some changes to restore balance. — DAGwyn 06:24, 1 September 2006 (UTC)Reply

It still has POV problems, especially "Memory Allocation". It's unfair to just remove the section (because Memory Allocation _is_ often criticized), but these points don't apply- for example, operating system kernels don't often use heaps (and have no malloc() or similar function). It's for this reason that operating systems, and many embedded targets simply cannot be written in languages that perform automatic garbage collection or RAII. 216.169.144.254 14:56, 26 October 2006 (UTC)Reply

If it often is a point of criticism, then it seems appropriate for this article, whether or not it is always justified. Indeed, I could "rebut" several of the criticisms, but haven't tried to do so, because that would turn the article into a flame war. — DAGwyn 21:05, 27 October 2006 (UTC)Reply

Move? edit

Is there a specific reason behind this article's title? If not, I think a better name would be Criticism of C programming language. --Gray Porpoise 17:52, 4 September 2006 (UTC)Reply

It was spun off from the main article "C programming language". As a subtopic the title seems okay to me. — DAGwyn 01:24, 5 September 2006 (UTC)Reply
Note that it has now been renamed to "Criticism of C". — DAGwyn 19:16, 29 September 2006 (UTC)Reply
Note that somebody has renamed it yet again, to "Criticism of the C programming language". — DAGwyn 20:37, 20 November 2006 (UTC)Reply

Use of Integers as Booleans edit

The article says nothing of the use of integers as boolean values.

Is that a criticism or just a feature? Note that Knuth's book "Concrete Mathematics" made heavy use of an analogous mathematical construct. — DAGwyn 20:59, 21 November 2006 (UTC)Reply
Combined with the unintuitive choice of precedence for bitwise vs logical operators (you would expect logical to be lower), ...
I meant to say that you would expect the precedence of the relational and equality operators to be lower than the bitwise ones. (See -- even when specifically thinking about it, I forgot the precise way in which the precedence is borked ;-) --DavidHopwood 02:21, 30 August 2007 (UTC)Reply
... it can hide common errors that would otherwise be caught by a compiler. --DavidHopwood 20:03, 29 August 2007 (UTC)Reply
The precedence is problematic, although one gets used to it (and parentheses can always be used when one is uncertain). These days many compilers issue warnings for the problematic combinations. There is some merit in the observation that a stricter syntax involving an explicit Boolean type, as seen in some other PLs, makes it harder for certain kinds of coding error to go undetected at compile time. The same could be said for mixed-mode arithmetic, where truncating conversion seems to catch a lot of people by surprise. Yet a lot of PLs support the latter. — DAGwyn 00:54, 30 August 2007 (UTC)Reply
The article is about criticisms of C, and this is a valid criticism -- albeit one that is probably quite a long way down the list. If the precedence is something you have to get used to, or sprinkle parentheses everywhere in case you misremember it, then it's far from ideal. I still very occasionally make this mistake (in cases such as "flags & FLAG_FOO != 0", intended to be "(flags & FLAG_FOO) != 0"), even after ~20 years of writing in C. That's how I know that MSVC++, for example, does not warn about this even at /W4.
In general, "X is like Y, and a lot of PLs support Y" is not a particularly convincing argument for X being a good idea. Perhaps X is not really like Y in the relevant sense, or perhaps Y is also broken, and one could be equally critical about the other PLs that support it.
As for mixed-mode arithmetic and implicit conversions, I think the trend in recent languages is for only widening (i.e. value-preserving) conversions to be implicit; a truncating conversion is an error without an explicit cast. That's what Java does, for example.
About the equivalence of 0/false and non-0/true being a feature, it is not one that I've missed in languages that don't have it. "a_boolean ? 0 : 1" and "an_integer != 0" are both IMHO clearer than using a_boolean directly as an integer or conversely. --DavidHopwood 02:21, 30 August 2007 (UTC)Reply
I didn't say the precedence was good.. Even early on, Ritchie and others noted that they had made a poor choice there. So the operator precedence is a valid criticism of C (and it's already in the article).
As to the integer/boolean confuting, it seems to be largely a matter of opinion. Note that the S language doesn't automatically coerce very many data types, but it does for integer/boolean even though it has them as distinct types. Note that your first rewrite is incorrect: a true boolean should be treated as 1, not 0. Anyway, it seems to be a somewhat common criticism, so I added this to the article (in a succinct way). — DAGwyn 23:19, 30 August 2007 (UTC)Reply
This reads as an issue purely of style. The language has always permitted "if(a != 0){ .. }". Could not one complain about the style some people use in languages that strictly enforce a boolean expression in if-statements when they write "if(something)", when it would be clearer to write "if(something == true)"? Idiom, common usage, etc, is as important in computer as well as natural languages: is the fact some people are ignorant, or make strange, debatable or perhaps even unacceptable use of a language really a bug with the language? mdf 19:51, 31 August 2007 (UTC)Reply
It's not just "style" meaning "aesthetics", since the claim is that C's approach makes undiagnosed errors more likely, which would certainly be a deficiency justifying criticism. As to "if(boolean_expr == true)", the " == true" is redundant (in a language with full Boolean support), unlike the " != 0" in "if(numeric_expr != 0)". I frankly would not design a C-like language without Boolean types (with conditional expressions allowed to have only Boolean type), even though I have decades of experience using C and am quite comfortable with it. But then I wouldn't specify any implicit conversion between types, either. Some "convenience" features cause occasional problems, and if they aren't actually needed then I don't want them. — DAGwyn 22:14, 31 August 2007 (UTC)Reply

Call-by-reference edit

Isn't the complete lack of call-by-reference one of the greatest ahortcomings of C? After all, it makes programs slower (as additional checks for NULL-pointers have to be included) and and tends to introduce errors in the source (if these checks have been omitted).

Especially since call-by-reference was already present in Pascal (and probably other languages as well) which is slightly older.

C's explicit use of pointers to obtain references was a simplifying concept. C++ added reference parameters, but it needed to do that to support certain operators on classes. Checks for null pointers is a red herring, as the reference-parameter equivalent would be something like a nonexistent argument (probably not even expressible); properly programmed pointer arguments usually don't need to be checked, and in other instances it is actually useful to have an in-band special signal available.
Actually Pascal and C were developed contemporaneously.
Fortran passed parameters by reference, which in some early implementations led to errors of its own kind:


 PROGRAM MAIN
 CALL SUB(2)
 I = 2
 PRINT ' I5', I
 END
 SUBROUTINE SUB(K)
 K=0
 RETURN
 END
or something like that, which could print "0" instead of the expected "2". Anyway, if there is a significant need for pass-by-reference that C cannot meet using pointer parameters, that could be a valid criticism, but the mere fact of being different from other PLs isn't a valid criticism.
Well, you kind of got my point: In languages with call-by-reference, it is simply impossible to pass NULL, therefore no checks are necessary.
But I cannot agree with your argument regarding the Fortran example -- as parameters are always c-b-r (in this specific implemtation), one should indeed expect K=0. --MushroomCloud 00:23, 8 December 2006 (UTC)Reply
For the record, the FORTRAN standard doesn't require call-by-reference. It specifies the behaviour (and it is a behaviour that lends itself to reference passing), but not the mechanism. One could write a standard compliant Fortran compiler that did copy-in-copy-out. -- GWO
As I said, it was a problem in some early implementations of FORTRAN, before there was even an ANSI standard for FORTRAN. The behavior illustrated by the example was actually encountered by several of us old-timers. The point of that is that pure pass-by-reference is often not what one wants either. With C, the programmer gets to choose between pass-by-value and pass-by-reference when he designs the function. — DAGwyn 22:08, 8 December 2006 (UTC).Reply
You can du so in languages like Pascal or Ada as well, but they do so in a clean and safe way, making it impossible to pass NULL, and thereby creating safer and more efficient code. --MushroomCloud 19:56, 10 December 2006 (UTC)Reply
I don't know why you're so hung up on passing a null pointer as argument, which can sometimes be a useful thing to allow (for example, to request use of a built-in default for that argument). As to unintended usage, C's pointers are powerful and dangerous for the same reason (namely, that the validity of pointer arithmetic relies on semantic constraints and on the pointed-to type only, not on type properties of any containing aggregate). So all sorts of erroneous usage is possible when the programmer doesn't think properly. But to some extent usage errors are possible in any language, for example accidentally interchanging the source and destination buffers for some buffer-copy function. — DAGwyn 21:16, 11 December 2006 (UTC)Reply
I want to note also that C does not necessitate run-time checks for null-pointer parameters; indeed a C compiler cannot automatically impose that since many programs require that null-pointer arguments be allowed. I guess you must be referring to a presumed need for the programmer to perform such checks, but there is no such need in general. (It might be prudent to do so when producing a library for use by others, or perhaps as part of some overall safety strategy that to be of much use would also have to include exception handling.) A correct program does not benefit from such checks, and for incorrect programs there is no automatic way to fix them at run time. There are a variety of tools available, including checks provided by many compilers, that can detect a wide range of programming errors, more than merely having "strong typing" could catch, and it is reasonable to expect people to use them (as well as procedural approaches such as code walkthroughs). — DAGwyn 21:27, 11 December 2006 (UTC)Reply

Undefined Behaviour section edit

  • Reaching the end of a function without finding a return statement, when the return value is used.

Almost any compiler less than 15 years old produces an error in this case, or at least a warning.

  • Reading the value of a variable before writing to it.

Again, most compilers raise warnings/errors about this as well.

If we're criticizing "ancient C" I suppose it's OK to leave those items in, but they are obsolete. --Shyland 11:00, 25 February 2007 (UTC)Reply

Actually there are zillions of possible instances of undefined behavior, but the article tries to pick out several that cannot be correctly diagnosed at compile time. In fact the C standard requires conforming implementations to accept programs that potentially trigger the above cases of undefined behavior, because in general it cannot determine at compile time whether u.b. will occur at run time or not (it depends on the dynamic flow of control, which can depend on the values of variables, and on linkage to other separately compiled modules that in general are not known when compiling the current translation unit). — DAGwyn 04:29, 26 February 2007 (UTC)Reply

Missing Features section edit

Come on, this whole list of "missing features" is silly. No graphics!!?? That's absurd. Any language which supported this entire litany of "missing features" would be a completely unimplementable, totally unusable mess. I believe there was an attempt to make a language which was all things to all people: it was called Ada...

Yes, there are some valid items in that list...but you'd get a different subset depending on who you talked to. --Shyland 11:14, 25 February 2007 (UTC)Reply

The article documents common criticisms of C, and indeed one that is often heard is the lack of any standard graphics support. Java, for example, tried to address this (they didn't get it right the first time or two), and Python has a "standard" graphics interface, so it's not an entirely unreasonable thing to request. You have also mischaracterized Ada, which initially did not specify any graphics support anyway.
Note that there are "rebuttals" for many of the criticisms; it isn't the purpose of this article to debate, but rather to document. It was spun off the main C article to reduce the overall negativity of the main article. — DAGwyn 04:36, 26 February 2007 (UTC)Reply
A problem with the "missing features" section is that the even with Java and Python, things like graphics or networking support are not a part of the language, they are a part of the acompanying libraries. I feel that the distinction is an important one, as the title of the article is criticisms of the C programming language, not the library. —The preceding unsigned comment was added by 194.203.201.92 (talk) 13:09, 23 April 2007 (UTC).Reply
Well, Java and Python seem to always come bundled with de facto standard graphics "packages" (although Java's has changed a couple of times). The fact that they are implemented as libraries isn't as important as their universal availability. C has no such standard graphics library; X-Windows might be considered a candidate, but in fact it isn't as widely available as it perhaps should be. (I don't know if the latest Windows releases include X server support, but you used to have to add it on from some third-party provider.) Anyway, it is indeed a fairly common criticism of C. — DAGwyn 19:30, 23 April 2007 (UTC)Reply
By the way, the language that is everything to everyone isn't called Ada, but Oz. --MushroomCloud 14:27, 26 February 2007 (UTC)Reply

I am also amazed at what appears in the "Absent features" section. It reflects a basic misunderstanding of the purpose of C. If C was required to have garbage collection, bounds-checking, closures, etc, then it would not be possible to efficiently implement another language with C. Also, trying to write an OS kernel with a garbage-collected language is too ridiculous to even consider. Xerxesnine 21:12, 17 March 2007 (UTC)Reply

That's not entirely true. Bounds checking is possible, in differently designed languages, without incurring much run-time overhead. So is garbage collection (via what are generally known as "on the fly" methods). Part of the perceived problem is that C has been widely used to write applications, not just "systems software". Of course these days we have Python, etc., but largely they were inspired by some of the very criticisms of C that the article documents. — DAGwyn 09:36, 18 March 2007 (UTC)Reply
When you say "without incurring much run-time overhead", what you mean is "in many circumstances the run-time overhead of bounds-checking is negligible", which is true. But remember we must account for other circumstances. There are other cases where bounds-checking deals a significant blow to performance. These cases are non-trivial and non-rare, and for this reason C does not do bounds-checking. The same principle applies to garbage collection, dynamic stacks, etc.
You have somewhat misunderstood the point of my comment above, which is that the mere suggestion that C should incorporate these higher-level features indicates a misperception of C's niche. One part of this niche is in implementing higher-level languages. Since a higher-level language would likely do its own bounds checking (in order to throw an exception, for example), this would render C's (hypothetical) bounds-checking needless and wasteful. In many cases it would not matter, but in many cases it would.
In short, the lack of higher-level facilities like bounds-checking and garbage-collection is not a shortcoming of C. It is a feature of C. Xerxesnine 23:45, 20 March 2007 (UTC)Reply
It is indeed possible to have compile-time bounds checking. In Ada, for example, variables can be limited to a range of values. If it is certain, that a an expression cannot be outside an array's range, the check can be made at run time. Consider:
I : Integer range 1 .. 10;
A : array (1 .. 20) of Integer;
-- ...
A (5 + I) := 1;
Here, the the expression will always be from 6 to 15, and therefore, no run-time check is necessary.
Additionally, checks may be supressed when indicated. --MushroomCloud 00:08, 21 March 2007 (UTC)Reply
Since the purpose of Ada is nearly opposite to the purpose of C, it seems you have misunderstood my point as well. The ability to walk through raw memory is the whole point of C --- you can't build an OS kernel without that ability. You can't write an OS kernel entirely in Ada. Bounds-checking is not an "absent feature" of C. The lack of it is a feature.
Incidentally, linking to a bounds-checking library is trivial (e.g, -lefence), so the point is moot anyway. The ability to use a variety of third-party memory management libraries, rather than having the compiler imposing such management, is a feature of C as well. Low-level, complete control, wet and wild.
Don't think for a moment that I am "advocating" for C. I am merely trying to clear up what appears to be widespread misperceptions about it. Xerxesnine 01:25, 21 March 2007 (UTC)Reply
I certainly understood the point, but keep in mind that I segregated this article from the main C article intentionally, to provide a less disruptive place to document criticisms that have some degree of validity, which may depend on point of view, purpose, etc. It isn't intended to pass judgment (except whether the criticism is reasonable enough to even mention) nor to debate within the article. In several instances, there is text that somewhat counters a criticism by explaining why things are as they are.
There are possible counterarguments to many of your arguments. For example, C could mandate bounds checking and pointer validation, but also provide an "escape" mechanism, such as "#pragma unchecked", and that would support the occasional need to violate a more restrictive model while by default imposing the model for other purposes. Much bounds checking could be performed at compile time. And C wasn't thought of as a target language until years after its invention, so those arguments don't justify the original decision.
Note that I've been using C continually since shortly after its inception, and have served on the C standards committee for decades. (We've heard a lot of criticisms of C and requests for changes! There are of course good reasons for much of the way C is specified, and the standards committee has tried to uphold them.) I'm a major proponent of C, particularly for systems work, but I also acknowledge that it has deficiencies (in some contexts), and it is worth noting them if for no other reason than to guide potential future language designers, who might be able to make better choices if they understand the consequences of past ones. — DAGwyn 20:51, 21 March 2007 (UTC)Reply

Automatic memory management edit

It is said in this article that C doesn't support automatic memory management. However, such thing is not language-dependent. It is feature of supplied libraries and system environment. Now we see that .NET Framework uses automatic memory management, and native Win32 platform doesn't do it, and actually all Win32-targeted languages have not automatic memory management, but all .NET-based ones have it. Actually memory allocation and releasing is call to functions, and how these functions are implemented is not language-dependent. If we have automatic memory management library, we can call it even from Assembler.

I'd say the most important part of automatic memory management is that you shouldn't have to call any kind of delete / free function. While libraries that let you do that in C exist, they don't (and couldn't) work correctly on all C programs if you replace all calls to "malloc" with a memory manager. In languages like C# and in particular Java, you have to use the memory manager, and the standard is designed to make one easy to implement. —The preceding unsigned comment was added by Mrjeff (talkcontribs) 23:21, 5 March 2007 (UTC).Reply
Yes, the model the criticism has in mind is garbage collection, where no-longer-referenced variables are reclaimed by the system, not requiring any explicit programmer action (such as calling free/delete). C does have automatic variables, but only within the stack-oriented procedure call hierarchy. — DAGwyn 23:45, 5 March 2007 (UTC)Reply

I agree with DAGwyn.In my opinion this should be changed to flaws of C not criticism of C.Criticism is bias and not neutral. —Preceding unsigned comment added by Andrew9019 (talkcontribs)

Err... what? It's the exact opposite. Criticism is neutral and flaws is not. Dlong 01:25, 17 June 2007 (UTC)Reply

Is this criticism? edit

Consider:

void strcpy(char *s, char *t)
{
    while (*s++ = *t++);
}

In other more "serious" programming languages (such as Ada, and in its extrapolation: Intercal) this is a slightly absurd statement, but in the eyes of a mathematician it's like getting a full formula of GOD!! Consider the symmetries: both args are char *, s and t occur in the same order in args and in boolexpr, same ops are performed on s and t in boolexpr of while. I used to regard C as a sunky primitive language, but I now am inclined to convert – this phantastique language might be the Ultimate PL in disguise!! I think I've found salvation, and Kernighan and Richie are prophets, hurray!! Said: Rursus 07:57, 27 June 2007 (UTC)Reply

A possibly valid criticism might be that C encourages concise coding with multiple operations performed within a single statement, and that can be abused to produce hard-to-understand code (witness the "International Obfuscated C Code Contest"). The "Economy of expression" section already covers that. By the way, see the index of coincidence page for a formula using Donald Knuth's bracket notation which is essentially the same as C's making relational expressions evaluation to 1 or 0. He co-authored a book "Concrete Mathematics" that introduced and made good use of this notation. — DAGwyn 14:50, 27 June 2007 (UTC)Reply
Yeah, now being in a serious mode, that might be a reasonable standpoint. Except that I, myself, pretty fluent in C, immediately understood what the code did! If a reader is not exactly fluent, the code (which is beautiful BTW ... really!) may be an example of a mystery code. On the other hand: an APL affiniado criticised the unintelligibility criticism on APL by stating: you must know the language to comprehend it, and an APL programmer may comprehend APL code. I think we should keep the section and the sample as they are, my previous expression was just an expression of joy over the paradox of "unintelligibility" combined with "beauty". We may argue whether "unintelligibility" is really a valid argument, but not in this article. Said: Rursus 08:24, 28 June 2007 (UTC)Reply
This is really cute and all, but the world doesn't quite work like this. Programs should also be understood by people without profound knowledge of the language. C makes this very hard, thanks to constructs like the above.
BTW: It wouldn't do apples and oranges justice to compare Ada and INTERCAL. Find out the reasons yourself. --MushroomCloud 14:39, 29 June 2007 (UTC)Reply
The language doesn't require that it be used cryptically; C programs can be quite readable if the programmer so chooses. Also, it doesn't take a "profound" knowledge of C to understand the example; indeed it's a textbook idiom that every C programmer should recognize. Obviously (as I believe K&R said) the practice can be carried to an extreme, and if indulged in carelessly can make code harder to maintain. Anyway, I think the article adequately covers this criticism. — DAGwyn 18:09, 1 July 2007 (UTC)Reply
Hehe. Not everyone who examines a program knows the language too well. Therefore, it should be as clear as possible. More importantly, there is nothing to be gained from writing the above instead of clearer code (like the one found later in the same section), hence there is no reason to write like it, hence it is bad.--MushroomCloud 05:47, 2 July 2007 (UTC)Reply

empty statements edit

Consider the following Ada-code:

for i in 1..10 loop
  Ada.Text_IO.Put_Line("Hello World!");
end loop;

Now, let us translate into C:

int i;
for(i=1;i<=10;i++)
  printf("Hello World!\n");

Ok, I'll withhold my opinion of C's for-syntax. Now, what easily happens is:

int i;
for(i=1;i<=10;i++);
  printf("Hello World!\n");

This, of course, is wrong, and corresponds to the following Ada-code (assuming i is used nowhere else):

for i in 1..10 loop
  null;
end loop;
Ada.Text_IO.Put_Line("Hello World!");

The ease of accidentally placing an empty statement is obvious, has no beneficial effects on the resulting machine code and is therefore bad. Opinions? --MushroomCloud 22:36, 4 July 2007 (UTC)Reply

It's one of those weaknesses thats easily remedied by indentation in your editor. -- GWO
I've written a huge amount of C code and haven't had that problem. Why would you put a semicolon there unless you meant it? Generally speaking, empty statements have legitimate uses, so it would be misguided to criticize their very existence. I always put an empty statement on its own line, for clarity, just as I write the controlled statement on a separate line from the controlling condition, but there are many C programmers who put them on the same line. In that case I would criticize the programming style, not the language itself. — DAGwyn 13:55, 6 July 2007 (UTC)Reply
I've written a huge amount of C code. Well that's probably your answer ;) I've never had that problem, but then I'm a compulsive user of braces and brackets. It's a valid criticism if you think compilers shouldn't compile programs that don't do what the programmer doesn't want them to. As a feature, it's not great it's hardly a massive misfeature. -- GWO
This is that kind of mistake one makes at 2 in the morning. The problem isn't that C allows empty statements. The problem is that they are assumed implicitly. In Ada (good example of minimising human error), blocks (like loops) cannot be empty, they can merely contain an empty statement (null). (Compare   and  ) --MushroomCloud 15:58, 6 July 2007 (UTC)Reply
What?  ; is an empty statement. {} is an empty block, and it is a statement, too. { ; } is a block only containing an empty statement. They do the same exact things.--Army1987 21:40, 13 August 2007 (UTC)Reply
If the complaint is that C differs from Ada (or from Pascal, or Lisp, or ...) then that's not a noteworthy criticism. If the complaint is that C doesn't prevent your writing valid code that nevertheless isn't what you meant to write, well, all PLs have that property, or else there would be no "bugs". Information theory tells us that to reduce the likelihood of accidents (corruption) resulting in valid messages, the encoding must contain a substantial amount of redundancy. The designer(s) of C wanted to minimize the amount of typing needed, so they didn't require much redundancy. That's why there is not even a requirement for a compound statement as the controlled statement of an if, for, while, or do...while, unlike other languages which require THEN...ENDIF, BEGIN...END, etc. There is still a fair amount of redundancy in C in absolute terms; random "line noise" has very little chance of producing a valid C program. Anyway, I think a criticism that C doesn't auto-correct typos would sound rather silly (although it should be noted if it is indeed a widespread criticism). — DAGwyn 22:20, 6 July 2007 (UTC)Reply
Yes, I know: C always assumes the programmer knows what she is doing. This, however, is a rather bold assumption. Everything that is better checked by a machine (like block nesting) should therefore be checked by a machine. And empty statements (which should be an exception rather than the rule) should stand out in code, rather than be assumed implicitly. --MushroomCloud 16:12, 7 July 2007 (UTC)Reply
What do you mean by saying that empty statements are "assumed implicitly"? You have to put an empty statement there. For instance, having label:, at the end of a function, without a semicolon following, is a syntax error. I guess what you mean is that the syntax for an "empty statement" ought to be more verbose. (Actually, there is clearly no need for an empty statement at all, since you can always write {} with the same effect.) Eric119 20:43, 7 July 2007 (UTC)Reply
I wouldn't mind {} as the syntax for an empty statement. What bugs me is the word “can” as opposed to “must.” If you type
if (a==b);
  printf("a=b");
then the second line will always be displayed. At least Watcom warns you. Nonetheless, loops, conditionals etc. should actually do something, therefore it should be explicitly stated if they do not. --MushroomCloud 13:46, 8 July 2007 (UTC)Reply
Well, I guess my point was that, technically, it is explicitly stated. A semicolon by itself is a statement whose behavior is to do nothing. But I agree that this situation is not ideal and would design things differently. There are a number of things like that but it's too late to change them. Eric119 03:43, 9 July 2007 (UTC)Reply
That's what the article is about :). So the question remains: Include it or not? --MushroomCloud 10:30, 9 July 2007 (UTC)Reply
Is it a common criticism, or just yours? (If the latter, that would be "OR".) Some thought is needed also on how to best express the issue. Perhaps: "Spurious semicolons, which some people seem prone to enter, can change the meaning of a program. — DAGwyn 14:33, 9 July 2007 (UTC)Reply

Largely wrong and ungrammatical edits edit

OK, I've reworded this again:

Many operations in C that have undefined behavior are not required to be diagnosed at compile time. In the case of C, "undefined behavior" means that the exact behavior which arises is not specified by the standard, and exactly what will happen does not have to be documented by the C implementation.

If this isn't of a suitable standard would someone explain what the phrase '"illegal" operations' is supposed to mean?

Secondly, the comment in brackets about array indexing is hardly relevant, unless someone is going to add some criticism of array indexing to this article. I believe it should be removed. Also, I still believe the sentence about heap memory management to be too long. 62.212.118.231 19:47, 17 July 2007 (UTC)Reply

I'm also changing the word 'lacks' in absent features. Using this words suggests that C is in need of these features; this is, at best, an opinion. 62.212.118.231 22:58, 20 July 2007 (UTC)Reply

It's getting better. I'll work on the memory allocation part. One issue is that the problem is not just with the users of the accidentally-shared chunk; also corruption of the bookkeeping used by the allocator itself can (and often does) occur, which can lead to clobbering of "random" unrelated data when pointers are overwritten, etc. — DAGwyn 22:05, 23 July 2007 (UTC)Reply

What's misleading with nasal demons? edit

A famous, although misleading, expression in the net newsgroup comp.std.c is that the compiler could cause "demons to fly out of your nose".

What is misleading about that sentence? Of course, it is quite obvious that no existing implementation ever causes demons to fly out of your nose on an instance of undefined behavior, so no-one would interpret that statement literally. And yet, if such an implementation existed, it could still claim to conform to the C standard, which defines "undefined behavior" as behavior, upon use of a nonportable or erroneous program construct or of erroneous data, for which this International Standard imposes no requirements.

Maybe the misleading thing is "compiler" rather than "program". Indeed a program potentially containing undefined behavior must be compiled correctly, unless the compiler can determine beforehand that the statement causing it gets always executed. For example

#include <stdio.h>
int main(void)
{
    int i = 3;
    if (0) {
        i = i++;
    }
    printf("%d\n", i);
    return 0;
}

must compile and work. I'm replacing "compiler" with "program" above. Isn't this what is 'misleading'? If nobody objects, I'll remove the "although misleading" part, too. --Army1987 20:49, 13 August 2007 (UTC)Reply

What's misleading is that to actually implement nasal demons would take an intentional act of engineering, whereas the true-life meaning of "undefined behavior" is that whatever happens happens, and is not constrained by any explicit guarantee. More realistic would be: trigger a fault (possibly leading to abnormal termination), or overwrite an unintended storage location. "Nasal demons" doesn't really help anybody to understand the issue. — DAGwyn 18:02, 14 August 2007 (UTC)Reply
Actually there are instances of undefined behavior which take an intentional act of engineering: for example, on some systems fflush(stdin); reads characters from stdin up to the next newline included and discards them; or printf("%2$d %1$d", this, that); can print that and then this. But your point is valid, but it should be better pointed out. Army1987 20:48, 14 August 2007 (UTC)Reply
Yes, a conforming implementation is free to define behavior for specific instances of "undefined behavior", but it is not obliged (by the C standard) to do so, and in the vast majority of instances they don't. This discussion is related to a sometimes-perceived general need for more "conformance categories" to give formal names to the different flavors of conformance. Perhaps "conforming with extensions", in the cases mentioned. — DAGwyn 21:42, 14 August 2007 (UTC)Reply
The standards body probably wasn't much interested in creating new stuff, but simply normalizing and documenting current practice, at least at that time. At most, (I'm speculating, not being one of the cognoscenti), they would elaborate to clarify (e.g., function prototypes). "This is how its done now and it's a seriously good idea you do the same thing, and here are some recommended things you should do too." Consider your "i = i++" (and related) stuff. This was probably left "undefined" because (a) the construct was hardly ever used (I don't recall any code like it, let alone any depending on a particular implementation), (b) has no clear cut 'real meaning' anyways. In this case, and others, to engineer a solution would probably constrain an implementation in other, unforeseen, ways, perhaps even breaking a massive pile of extant code, which would likely lead to a poor acceptance of the holy document, and a massive waste of time on the part of committee participants.
The interesting thing about C, and even C++, is that once you get past the actual language, you are basically free to engineer on your own. That IO, memory, and other infrastructure was not bolted directly to the language is the reason why this is true, and is in fact the true power of C (and C++), and (as noted above by others) why it can be used for "systems" work in the first place. If you hate the standard library, you can write your own (and some people have done just that); if you hate the language itself, there isn't much other choice available to you beyond inventing a poor imitation.
This suggests that the "criticisms" be carefully categorized to "criticisms of the language" and "criticisms of the standard library". Given the intimate connection C has with the underlying computational substrate, one expects that any in the former category would amount to criticizing computing itself -- or at least the Committee's implicit design of the computer C programs are run on. Complaints in the latter category probably have more substance, but like a wiki, "if you don't like it, fix it yourself" is a cogent rebuttal in most cases, and one not as accessible to higher-level languages. mdf 13:12, 16 August 2007 (UTC)Reply
I have been a member of the C standards committee for over 20 years. It is true that we tried not to invent new features, except in some cases where there seemed to be a pressing need, and also that the C standard was constrained by the existence of a large amount of C code well before the standardization process even began. We divided the base Unix standard C library between the C and the POSIX standards groups, even though we knew of several ways the existing standard library could have been improved. The main goal was to get everybody to actually use the standard, not to invent an academic specification that would be largely ignored.
While the standard C library is largely orthogonal to the language proper, so is the preprocessor. They are all considered part of one standard, and so long as one is clear about which component or feature is being criticized, there is no real need to separate the criticisms into those categories. Some things such as setjmp/longjmp are in effect linguistic features that just happen to be implemented using the library interface. — DAGwyn 15:39, 16 August 2007 (UTC)Reply

Tools for mitigating issues with C edit

In this section is the statement: "There are dialects of C, such as Objective-C and Cyclone...".

I don't think that Objective C is a dialect of C. Rather Objective C and C++ are supersets of C which are implemented as pre-processors. In other words they are extensions that add object oriented functionality to C but don't change the language. This is why you can always use C when programming with them. Is this correct?Senor Cuete (talk) 03:52, 16 May 2008 (UTC)Senor CueteReply

I don't really know about Objective C, but C++ is not implemented as a preprocessor nowadays, and has advanced far being just adding object orientation. There is no particular reason why a C++ compiler would have to also support C. Eric119 (talk) 04:10, 16 May 2008 (UTC)Reply
"Derivatives" might be better than "dialects", but I don't think it's wrong enough to need correction. By the way, some valid C code is not valid C++ code, and some is valid but is given different sematics by the two languages. C++ is not a strict superset of C. — DAGwyn (talk) 20:09, 16 May 2008 (UTC)Reply