LWN.net Logo

Why learn C? (O'Reilly Radar)

Why learn C? (O'Reilly Radar)

Posted Jun 29, 2012 7:09 UTC (Fri) by kleptog (subscriber, #1183)
In reply to: Why learn C? (O'Reilly Radar) by HelloWorld
Parent article: Why learn C? (O'Reilly Radar)

You're just denying reality here. C lacks tons of features that make everyday things much easier to write and debug and less error prone, such as automatic memory management, bounds checking, a sane type system, a module system, exception handling, closures etc.. These things were invented for a reason.
I think that's kind of the point. All those things you refer to simply do not exist at a hardware level. If your goal is to teach people how computers actually work then you need to use a language whose model resembles that of the underlying machine, and C does that.

FWIW, I think it would be instructive for new programmers to think about, for example, how you would actually implement things like exception handling in C, just so they appreciate what is being done for them. Many of the things you describe are decidedly non-trivial.


(Log in to post comments)

Why learn C? (O'Reilly Radar)

Posted Jun 29, 2012 7:51 UTC (Fri) by HelloWorld (guest, #56129) [Link]

> I think that's kind of the point. All those things you refer to simply do not exist at a hardware level. If your goal is to teach people how computers actually work then you need to use a language whose model resembles that of the underlying machine, and C does that.
My comment was a response to HenrikH's comment where he questioned the productivity advantages of modern high-level languages. I didn't mean to debate the utility of C as a teaching tool.

Besides, I don't think your comment is very convincing either. The problem is that C sucks even as a low-level language. There's no reason for not having a sane module or type system in a low-level language, not to mention the various C antifeatures like the stupid syntax and the preprocessor.

Why learn C? (O'Reilly Radar)

Posted Jun 29, 2012 8:42 UTC (Fri) by dgm (subscriber, #49227) [Link]

A list of features is not very convincing, either. Real World measurements, _that_ would be convincing! Show me measurements of effort put into creating real applications in different languages and we can start to talk.

Why learn C? (O'Reilly Radar)

Posted Jun 29, 2012 21:10 UTC (Fri) by tjc (subscriber, #137) [Link]

I know I shouldn't be feeding trolls, but why do you think C's syntax is "stupid?" The only thing that really stands out to me as not-so-hot is the prefix pointer declarator.

Why learn C? (O'Reilly Radar)

Posted Jun 29, 2012 23:38 UTC (Fri) by HelloWorld (guest, #56129) [Link]

I don't know why I'm even responding to this, given that you're calling me a troll without any justification.

Anyway, the main problem with C is its declaration syntax. Let's take a declaration like

void (*signal(int, void(*)(int)))(int);
This is ugly for two reasons. One is that parenthesis are required to distinguish void *(int) from void(*)(int). The other is that the tokens that describe the function's return type are split up: the void(* in the beginning and the )(int) in the end belong together, which is harder to figure out than necessary. Using a postfix pointer declarator fixes the first problem but not the second:
void signal(int, void*(int))*(int);
This is fixable by using another syntax for simple declarations: i int; instead of int i;. That would lead to a declaration like this:
signal(int, *(int)void) *(int) void
This also offers the advantage that the name being declared is always at the beginning of the line. It also makes preprocessor macros that involve declarations easier to write.

Another problem with the C syntax is that in function parameter declarations, foo[] means the same as foo*, while everywhere else it doesn't. People keep confusing arrays and pointer due to this (though the implicit conversion from foo[] to foo* also promotes this).

I also find it ugly that while both :? and if/else exist, there is only a switch statement and not a switch expression.

And just to be clear: the C syntax is actually not the greatest of C's problems. The lack of sane type and module systems is a much greater burden.

Why learn C? (O'Reilly Radar)

Posted Jun 30, 2012 17:48 UTC (Sat) by tjc (subscriber, #137) [Link]

> signal(int, *(int)void) *(int) void

That's going to be hard to parse. The lexer is going to return a token with the value "signal", but the parser is going to be sitting at the top level without any context in which to evaluate it. If it's not a reserved word then it must be an identifier, but nothing else is known about it without peeking further ahead into the input stream.

Something like this would be more practical:

func signal(int, *(int)void) *(int)void

I personally don't mind that C (and C-like languages) anchor declarations with the type. It's still a left-to-right parse, with the single exception of the type. The "var|func ... <complete return type>" syntax is probably better, but I've been looking at "<type> ..." for so long that it seems natural to me. It also allows you to do things like this:

int i, j;

As far as the foo * vs. foo[] thing, that's not really a syntax problem, it's a semantic problem, given that arrays decay to a pointer to the first element in most (but not all; e.g. sizeof(foo)) cases. I agree that that could be changed, and it would be better in most cases. I usually write array parameters as foo *, just because that's what they really are inside the function.

I'm not aware of the difference between a switch statement and a switch expression, so I can't comment on that. I guess I better start "googling."

Why learn C? (O'Reilly Radar)

Posted Jul 1, 2012 11:15 UTC (Sun) by HelloWorld (guest, #56129) [Link]

> That's going to be hard to parse. The lexer is going to return a token with the value "signal", but the parser is going to be sitting at the top level without any context in which to evaluate it. If it's not a reserved word then it must be an identifier, but nothing else is known about it without peeking further ahead into the input stream.
I fail to see how conventional C syntax is any better. In a declaration such as foo *bar;, you have exactly the same situation, and to be honest, I don't even see why it's supposed to be a problem.

The only problem I see with this syntax is that it's ambiguous: there's no way to know whether foo(bar)*baz; is a declaration or a statement without looking at the preceding declarations in order to find out whether bar and baz are variables or typedef-names. Alas, conventional C syntax has the same problem in declarations such as the above-mentioned foo *bar;.

It's also fairly easy to disambiguate it using a syntax such as
foo: (bar)*baz;
That would clash with the goto label syntax, as foo: bar; is valid C code. However, this is not a problem: bar; is a statement without effect, so there's no point in writing code like that, therefore a line like that should be parsed as a declaration.

Why learn C? (O'Reilly Radar)

Posted Jul 1, 2012 22:30 UTC (Sun) by tjc (subscriber, #137) [Link]

I can't think of a situation in C where an expression that begins with a type specifier is anything other than a declaration. I could be overlooking something, but I'm looking at the grammar in appendix A13 of K&R, and I don't see anything.

Why learn C? (O'Reilly Radar)

Posted Jul 1, 2012 22:49 UTC (Sun) by HelloWorld (guest, #56129) [Link]

> I can't think of a situation in C where an expression that begins with a type specifier is anything other than a declaration.
Uh, so? In a declaration like foo *bar, you still have to know whether foo is a typedef or a variable name in order to know whether it's a multiplication or a declaration.

Why learn C? (O'Reilly Radar)

Posted Jul 1, 2012 23:02 UTC (Sun) by tjc (subscriber, #137) [Link]

The compiler has this information available to it in the symbol table.

Why learn C? (O'Reilly Radar)

Posted Jul 1, 2012 23:20 UTC (Sun) by HelloWorld (guest, #56129) [Link]

I know, this is the well-known lexer hack. I still don't see how the syntax I've proposed is supposed to be any more problematic than conventional C syntax.

Why learn C? (O'Reilly Radar)

Posted Jul 2, 2012 20:36 UTC (Mon) by tjc (subscriber, #137) [Link]

The type specifier in a C declaration acts as a surrogate for the missing 'var' or 'func' keyword, which makes it possible for the parser to recognize the declaration without requesting a lot of extra tokens from the lexer.

Why learn C? (O'Reilly Radar)

Posted Jul 2, 2012 21:23 UTC (Mon) by HelloWorld (guest, #56129) [Link]

I think that this is only a problem when using top-down parsers. A bottom-up parser should handle this situation easily.

Why learn C? (O'Reilly Radar)

Posted Jul 3, 2012 15:46 UTC (Tue) by tjc (subscriber, #137) [Link]

Yes, it could be made to work, but it would have to be a backtracking parser, and it would probably be slow. Most bottom-up parsers (such as those produced by bison) are LALR(1), which only has one token look-ahead.

Why learn C? (O'Reilly Radar)

Posted Jul 1, 2012 22:59 UTC (Sun) by tjc (subscriber, #137) [Link]

I wish there were some way to edit posts after posting so that my mistakes are not permanently recorded for posterity. :)

I should have said, "I can't think of a situation in C where a statement that begins with a type specifier...."

Why learn C? (O'Reilly Radar)

Posted Jul 2, 2012 9:30 UTC (Mon) by nix (subscriber, #2304) [Link]

Quite, thus ruling out sizeof().

Why learn C? (O'Reilly Radar)

Posted Jun 29, 2012 11:28 UTC (Fri) by adobriyan (guest, #30858) [Link]

> Many of the things you describe are decidedly non-trivial.

Seeing small, unknown C project called Linux the kernel from inside,
I agree that C sucks even as low-level language.

Multiple return values.
Less stupid preprocessor, more compile-time evaluation!.
Precise alignment and offsets of structure fields (constant and "modulo by" constraines).
Less "undefined behaviour" beartraps!

All of this could be added without sacrificing "close to machine" property some love so very much.

Why learn C? (O'Reilly Radar)

Posted Jul 1, 2012 2:55 UTC (Sun) by vonbrand (subscriber, #4458) [Link]

Multiple return values.

You can return a struct... and multiple return values would require handling multiple values all over the place (asignments, comparisons, ...). Nifty, but definitely not "low level." C is OK as is here.

Less stupid preprocessor, more compile-time evaluation!

The preprocessor is decidedly not stellar. Better use m4(1) perhaps? Or just chuck it altogether (given const and enums, and inline functions, its use is mostly for #include nowadays). Plus current compilers are quite smart at getting rid of useless code and constant folding, so "compile time evaluation" is given much more than you perhaps realize.

Precise alignment and offsets of structure fields (constant and "modulo by" constraines).

Sorry, but if you want a low-level, efficient language, you have to give the compiler leeway to accomodate the architecture's quirks.

Less "undefined behaviour" beartraps!

Ditto.

Why learn C? (O'Reilly Radar)

Posted Jul 1, 2012 12:22 UTC (Sun) by HelloWorld (guest, #56129) [Link]

> You can return a struct... and multiple return values would require handling multiple values all over the place (asignments, comparisons, ...). Nifty, but definitely not "low level." C is OK as is here.
This has nothing to do with high-level-ness. It doesn't require dynamic memory allocation or other fancy run-time implementation techniques and you don't lose any control over your code.

> Sorry, but if you want a low-level, efficient language, you have to give the compiler leeway to accomodate the architecture's quirks.
If one doesn't specify the data structure layout, the compiler would still be able to decide by himself what to do.

Why learn C? (O'Reilly Radar)

Posted Jul 1, 2012 20:42 UTC (Sun) by kleptog (subscriber, #1183) [Link]

>> You can return a struct... and multiple return values would require handling multiple values all over the place (asignments, comparisons, ...). Nifty, but definitely not "low level." C is OK as is here.

> This has nothing to do with high-level-ness. It doesn't require dynamic memory allocation or other fancy run-time implementation techniques and you don't lose any control over your code.

Returning multiple values is something that would require ABI support. Only values in the registers can be returned because the callee stack frame vanishes at return. Returning structs is already something poorly supported, because if it doesn't fit in registers, where do you store it then? The reason C++ can do it is because new/delete are part of the language, as are (copy) constructors. (I believe it's done with hidden extra parameters).

It would also require making a list a first class object in the language.
You could possibly come up with an ABI that supported returning multiple values in a way that was an improvement over what you can do already and make it work on all the myriad of processors in existence, but I just don't see the demand.

I think C's simple, predictable ABI is key to its continuing popularity. Any language, including dynamic languages, can call into a C library. If you have a C++ library it's already much harder, and calling from (for example) a python script into a perl library is essentially impossible.

Why learn C? (O'Reilly Radar)

Posted Jul 1, 2012 20:56 UTC (Sun) by HelloWorld (guest, #56129) [Link]

> Returning multiple values is something that would require ABI support.
Uh, so what?

> Only values in the registers can be returned because the callee stack frame vanishes at return. Returning structs is already something poorly supported, because if it doesn't fit in registers, where do you store it then?
On the stack of course. Also, returning structs isn't "poortly supported" at all, it works just fine.

> The reason C++ can do it is because new/delete are part of the language,
That's simply nonsense.

Why learn C? (O'Reilly Radar)

Posted Jul 1, 2012 22:24 UTC (Sun) by nix (subscriber, #2304) [Link]

To be fair, returning structures was poorly supported once. Of course that was in about 1980, but it explains some properties of the standard C and POSIX library (e.g. why stat() does not return a 'struct stat').

Why learn C? (O'Reilly Radar)

Posted Jul 1, 2012 22:38 UTC (Sun) by juliank (subscriber, #45896) [Link]

I'd say another reason is that it's much easier to check for errors if your function returns some integer and passes the real result via a pointer.

Why learn C? (O'Reilly Radar)

Posted Jul 2, 2012 9:29 UTC (Mon) by nix (subscriber, #2304) [Link]

Well, if there's only one error, it's easier to use the function if you just return the pointer or NULL.

Structures and results

Posted Jul 12, 2012 16:44 UTC (Thu) by alex (subscriber, #1355) [Link]

Or to emulate old-school styles return NULL and set the global errno ;-)

Why learn C? (O'Reilly Radar)

Posted Jul 12, 2012 20:04 UTC (Thu) by hummassa (subscriber, #307) [Link]

HRESULT feelings.

Why learn C? (O'Reilly Radar)

Posted Jul 12, 2012 20:08 UTC (Thu) by hummassa (subscriber, #307) [Link]

> On the stack of course.

Actually, IIRC, if the struct/class instance fits in one or two registers, those are used to return it; if it does not fit, the caller reserves the space just below the return address/stack frame on the stack (so the callee knows where to put it).

Copyright © 2013, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds