
Teaching C (2016) - ingve
https://blog.regehr.org/archives/1393
======
pjc50
C development, like most languages, isn't really "taught" at all. You might
have some teaching on the structure of the language and a basic getting
started course on main(), but that's just the beginning. Everything from there
up seems to be self-taught, either from the internet, code examples, or
working it out from first principles.

There are a lot more risks in C than more recent languages. Koenig's book "C
Traps And Pitfalls" [https://www.amazon.co.uk/C-Traps-Pitfalls-Andrew-
Koenig/dp/0...](https://www.amazon.co.uk/C-Traps-Pitfalls-Andrew-
Koenig/dp/0201179288) was extremely useful to me when I was learning the
language (available at my local library!). I don't know if there's a more
modern version that takes into account recent changes to the C standard.

I note that a lot of the time in embedded work you don't get to use the latest
version of the standard because you're using a weird or obsolete toolchain
that doesn't support it. Or architectures like PIC, where your stack is
hardware limited to 8 levels and indirect addressing is inefficient.

I think a lot of the "pure C" people are disguised as electronics engineers -
doing PCB design _and_ microcontroller programming together.

~~~
jackhack
>>Everything from there up seems to be self-taught, either from the internet,
code examples, or working it out from first principles.

But to be fair, can't that be said that nearly everything is self-taught? From
Physics, to mathematics, to music performance and theory, to learning to ride
a bicycle or drive a car -- we can read but it takes some time to internalize
the structure of each discipline and "own" it.

>>in embedded work you don't get to use the latest version I work in C77, and
I'm reminded of how far C (and C++) has come each time I have to #define that
fancy new-fangled "boolean" type.

>>I think a lot of the "pure C" people are disguised as electronics
engineers... Agreed, this is exactly right. Most if not all of the pure-c
world is due to embedded micros with strict limitations (<1k RAM, etc.)

~~~
tnova
> I work in C77

Do you mean C89? I've never heard of C77 and a quick Google search came up
with nothing.

~~~
rpeden
It looks like the author removed the bit about C77 from their post.

Although ANSI C wasn't a thing until 1989, the language had been around since
1972.

The original K&R book was published in 1978, and if you read it, you'll see C
that's noticeably different from C89 or newer. 'C77' was probably just a fun
bit of shorthand pjc50 used to describe old, K&R style C. Or at least C that's
missing some ANSI features.

~~~
geezerjay
This was the very first time I ever saw anyone using the term C77. I really
doubt the term was used knowingly instead of mixing up C with F77.

------
sacado2
C is a weird language, in the job market. It's at the core of all our
electronic infrastructure, it's important to learn it if you want to be a
serious developer, yet nowadays you can hardly find a job that is "pure C".

So, in universities, you have either students who don't see the point, because
they'll do java or PHP or JS at their daily jobs, or students who get a little
too excited by it, almost specialize in it, and can hardly find a job that
fulfills their excitment.

~~~
simias
A lot of low level embedded programming is effectively "pure C". I think the
problem is that these aren't usually entry-level jobs for people without
experience. It doesn't help that schools prefer to put the emphasis on
languages like PHP or JS because they're easier and almost guarantee that
people will find a job immediately regardless of their background. It's just
the path of least resistance.

But as somebody who mostly writes C for a living and specializes in embedded
programming I can assure you that there's no shortage of employment offers.

~~~
sacado2
I didn't mean it in the sense "C developers can't find a job", but in the
sense professional C programing is a niche; low supply, low demand. When
you're a freshly graduated student and there are 10 companies at 30 km around
that are ready to recruit you for c#/js stuff, and none for C stuff, you tend
to think "there is no job in C", even if there are 2 or 3 companies working in
the embedded field that were ready to recruit you, with an even better salary,
but 60km from here.

Maybe I'm wrong, though.

~~~
simias
No you're right but from my point of view (I've been a professional C coder
for about 13 years) it's not so much that there aren't many C jobs out there,
it's more that there's an avalanche of "c#/js stuff". In absolute numbers I
would be surprised if there was a significant reduction in number of C jobs
available in the past decade.

There's also the fact that there's comparatively little innovation and hype in
the C sphere of influence. C rarely makes the headlines these days while every
other week you have a fancy new JS framework.

~~~
user5994461
There is location to keep in mind. There is the defense and aerospace industry
concentrated in a few hubs, that should offer a stable supply of C jobs.

Everywhere else, not so much.

~~~
simias
Embedded in general and IoT in particular are big these days and even though
modern "controllers" are perfectly able to run scripting languages there's
still a lot of low level C going on. If you need to write a device driver
you're probably not going to do it in Javascript. You can argue that it's a
niche but it's a rather large one.

C is not fully COBOLized yet.

------
notacoward
It's pretty important to note this is about _how_ to teach C, not _why_.
Should schools be teaching C at all? I would say yes, not as an introductory
language but as a precursor to studying kernels or databases or compilers.
Real-life examples of these are mostly written in C, and studying such systems
is IMO a necessary part of a CS curriculum. Therefore, _at some point_
students need to learn C. They should certainly have the option, so we still
need to address the question of _how_ it should be taught.

With regard to that question, the OP seems pretty spot one. The identification
of certain codebases as good or bad matches my own experience with most of
them. The advice to use static analysis and to avoid preprocessor abuse is
sound. There are only a few things I'd add.

* You can't really learn C without also learning to use a debugger - probably gdb. That _must_ be part of the lesson plan.

* A more in-depth discussion of good error-handling and memory-management practices would be worthwhile, since C itself doesn't provide these.

* It can be very informative to implement some of the features found in other languages in C. Examples might include a simple form of object orientation, or a map/dict/hash, or a regex parser. Besides their value as a form of practice, this would expose students to some of the issues and decisions involved in making these a built-in part of a higher level language.

~~~
eternalban
> You can't really learn C without also learning to use a debugger

News to me.

I learned C in '85 from the K&R book and the project lead for our little
startup's Fortran to C translator. No debuggers were involved as far as I can
remember.

[p.s. as to "why" teach C. I know many languages at this point, but that
initial exposure to C necessitated a deeper understanding of 'the machine',
memory management, etc. The core of C is fairly straight forward and imho an
excellent pedagogical vehicle for a 'substantial' understanding of
"programming".]

~~~
canhascodez
The machine being used is completely incidental to programming. Dijkstra used
a fountain pen.

Which is more fundamental, the machine, or its mathematical abstraction? Why
should people learn C, and not Lisp?

~~~
eternalban
I wonder if Dijkstra used paper clips or rubber bands for "linking". (CS =/=
Programming)

~~~
canhascodez
Perhaps you could do me the favor of answering my question.

~~~
eternalban
Why should I bother with a red herring? We were discussing programming and not
computer science.

~~~
canhascodez
Why teach C and not Lisp?

------
jasode
The author's main paint is _pedagogy_ of teaching C as opposed to industry
relevance of C.

 _> The other day Neel Krishnaswami mentioned that he’s going to be teaching
the C class at Cambridge in the fall, and asked if I had any advice about that
topic._

Some googling found a C/C++ class by Neel Krishnaswami[1]. The description
says 10 lectures so I'm guessing roughly ~10 hours of instruction. The
prerequisites for the class are "none". You can also browse the pdfs of class
lectures and past exams to get a feel for what the professor is teaching.

With that in mind, we then consider Regehr's advice:

 _> My main idea is that we need to teach C in a way that helps students
understand why a very large fraction of critical software infrastructure,
including almost all operating systems and embedded systems, is written in C,
while also acknowledging the disastrously central role that it has played in
our ongoing computer security nightmare._

The noble goal of "traps/pitfalls/disasters of C" isn't really possible to
weave into an _introductory_ course if a class is currently structured with
~10 hours. You have some hard time constraints there. You'd have to _remove_
some topics ... e.g. maybe remove linkers?, STL?, metaprogramming? -- or --
make the class much longer ... e.g. more hours?, more homework?, more case
studies?

An _" Introduction to programming using C syntax"_ is one type of class that
requires a baseline of time to each.

An _" Introduction to industrial-grade software engineering using C best
practices"_ is another type of class with its own heavy time commitments.
Teaching the topics of correct/incorrect uses of C would take even more time
than the learning the syntax of C.

Regehr's essay is well-intentioned ("hey, you should teach this very important
topic <X-prime> related to topic <X>") -- but he doesn't actually tackle how
to squeeze it all into a finite time-constrained class.

[1]
[https://www.cl.cam.ac.uk/teaching/1617/CandC++/](https://www.cl.cam.ac.uk/teaching/1617/CandC++/)

~~~
neel_k
Hello,

You can see the current version of the class at:

[https://www.cl.cam.ac.uk/teaching/1819/ProgC](https://www.cl.cam.ac.uk/teaching/1819/ProgC)

I've moved to a style where the lectures are recorded and the lecture hours
have been replaced with lab sessions. I've also mostly[1] removed the C++
content and replaced it with more C. Both the videos and the labs should be
available for everybody.[2]

This gives more time for tooling (eg, ASan/MSan/UBSan/valgrind), as well as
for various low-level topics like memory management (eg, arenas, reference
counting and mark-and-sweep) and data-structure layout and cache optimizations
(ie, the reasons why people still use C). Also there's a heavy focus on the
lack of safety and undefined behaviour -- beyond the lecture devoted to it,
this comes up in basically every lecture.

[1] There are still 2 lectures on C++. If you think that it is impossible to
learn C++ in 2 one-hour lectures, you are correct. The pedagogical theory at
work is basically "Dumbo's magic feather": the goal is to give students enough
self-confidence that the year after they won't be afraid to consider doing a
final year project using C++ (eg, modifying a web browser), which is the point
at which they will _actually_ learn C++.

[2] I'm not totally sure how I feel about this. On the one hand, obviously I'm
happy anyone can access these resources.

But on the other, it's really easy to say subtly not-quite-right things when
lecturing. If it's ephemeral, then this is harmless since the effect of
lectures is just to cue students too remember what to look up when they are
programming on their own, but if they can re-watch the video then there's a
bigger risk of burning in the wrong idea.

I suppose the long-term thing is to pre-write a script for each lecture, maybe
even turn it into a book.

~~~
opheron
Cool to see you show up to respond!

Regarding the bit about "subtly-not-quite-right things when lecturing": IMHO,
it's too tall an order to ask professors to get everything in their lectures
exactly right. It seems more reasonable to take a page from good journalists -
get as much right as possible the first time around, acknowledge if you
discover something was wrong, and provide corrections with context.

Ultimately, I think it's up to students to remember that everyone can be
wrong, even professors, and to trust but verify. :)

------
pjmlp
In my university, back in the mid-90's teaching C was already seen as
outdated.

First year students got Pascal in the first semester and C++ on the second
one, followed by Caml Light, Lisp, Smalltalk, Prolog, MIPS and x86 Assembly,
PL/SQL, while those taking compiler design classes would also dive into many
other ones.

OS design, data structures and distributed computing classes assumed that
having learned C++, any student would be able to downgrade themselves into C
level on per-case basis.

C only became industry relevant thanks to the widespread of UNIX clones, and
in platforms like ChromeOS, Windows, Android, its relevance is slowly fading
away.

Still it is going to be around for as long as we need to target POSIX
platforms, which is why I follow with interest any attempt to make it safer,
as I would wish my computing tools not to be weakest link, if they happen to
be written in C for whatever reason.

~~~
simias
> In my university, back in the mid-90's teaching C was already seen as
> outdated.

Given the examples that follow it seems more of an ideological stance that a
practical one. C is dead so let's teach Pascal, Lisp, MIPS assembly and
Smalltalk?

From a language theory standpoint C is pretty clunky but in terms of getting
stuff done it's still one of the most mainstream languages out there.

>having learned C++, any student would be able to downgrade themselves into C
level on per-case basis.

That's sort of how I learned C in the first place where I see where you're
coming from but I don't think that's good general advice. "Don't learn C,
learn C++ and figure it out from there" is sort of like saying "Don't learn
Italian, learn Latin and figure it out from there". C++ is a beast of a
language, if people are interested in C they should learn C.

>C only became industry relevant thanks to the widespread of UNIX clones, and
in platforms like ChromeOS, Windows, Android, its relevance is slowly fading
away.

I sort of agree but I'm more of a glass half full type of guy, I think C is
less relevant not because it's fading away but because other languages are
taking a lot more space nowadays. What used to be considered "scripting
languages" are commonly used to build complex applications because we have a
lot more RAM and processing power than we used to. Still, kernels and low
level code are still commonly written in C or, sometimes, C++ because you need
good performance and/or tight control over the application.

~~~
pjmlp
> C is dead so let's teach Pascal, Lisp, MIPS assembly and Smalltalk?

Have you missed the time reference?

Java still wasn't invented, Smalltalk had companies like IBM selling products
written in it.

MIPS was being adopted across UNIX workstations.

People still though it was worthwhile to buy Common Lisp implementations.

Regarding language comparisons, actually C++ is Italian and C Latin.

~~~
roenxi
_puts on grumpy C programmer hat_

C is C and C++ is C++. The analogy breaks down in a pretty major way because
Latin has no native speakers, but important work is done in C. They didn't
stop speaking Latin because it had problems as a language, they stopped
because the cultural apparatus behind Latin collapsed after an exceptionally
long period of dominance that Italian speakers never achieved.

I'd like to believe C has a stronger future in the academic world because it
is simpler than C++, but also because C is a designed language and C++ is a
cobbled-together language, and maybe that counts for something in a field
where people call themselves engineers.

Anyone who sees C as a 'downgrade' has badly misunderstood what design means
as an engineering concept. It doesn't mean 'does everything', it means that
strategic choices were made early in the process after careful consideration.

* Serious hat *

C has a pretty well defended place in the world - it is an excellent choice
for manipulating RAM and controlling the size of variables. C++ isn't as good,
because its features add a lot of complexity that isn't really desirable when
you have a problem that C can handle.

I wouldn't use it for string parsing. Or GUIs except as an afterthought on a
project that used C for a good reason.

~~~
blub
C's well defended place is unfortunately mostly defended by folklore,
nostalgia and a desire for one-upmanship. There are several good languages
available today that can successfully replace C - including at controlling RAM
or the size of variables

P.S: there's a book called "The design and evolution of C++" which you should
probably read. Where can one learn more about the design of C?

~~~
simias
I disagree, C is popular for the same reason that QWERTY is more popular than
DVORAK or Colemak or that x86 is more popular than ARM (talking purely from an
IA perspective). It's not folklore or nostalgia, it's just that it was here
first, there's a ton of legacy applications that rely on it and the cost of
the switch is seen as a large, one time cost vs. the small benefits it would
bring over a longer period of time.

I'm a huge fan of Rust and I can only dream of having all C codebases in the
wild ported to it some day but I'm still writing C at work because it's
faster, easier (vendors provide C libraries and code, not Rust) and it's
easier to hire C coders than Rust ones.

>P.S: there's a book called "The design and evolution of C++" which you should
probably read. Where can one learn more about the design of C?

I'd be surprised if C was really ever "designed" the way we would design a
language these days. Basically it was a fork of earlier languages tweaked to
more conveniently model the hardware of the time. It was more about getting
the job done at the time than making an innovative language. At least that's
what I gathered from what I know about the early days of C and it's also
fairly apparent in the way the language itself is designed (the whole
pointer/array shenanigans come to mind). C is many things but it's definitely
not elegant or even clever.

~~~
pjmlp
Except that is yet another folklore, as C wasn't there first in any form or
fashion.

There is an history of 10 years of systems programming languages, preceding
it. Prooving one does not need to throw security out of the window in systems
languages.

Had Bell Labs been allowed to sell UNIX, instead of giving it away for a
symbolic price and C would have been a footnote on history of system
languages.

~~~
simias
The parent was talking about "nostalgia" and "replacing C" so I assumed they
were talking about more recent languages like Rust, C++, D, Go, Zig and all
these newer system languages.

I agree that if we're talking about why C took over in the first place it's a
different discussion.

------
enriquto
It is silly to start teaching in C. You must first learn assembler and then
you understand the godsend that C is. When you write C, you should be thiking
what happens in assembler, and then writing it beautifylly in C.

In parallel to this low-level thread of learning, you have to learn other
high-level languages, of course.

~~~
cm2187
And you will have disgusted half of the class from programming by the end of
your first assembler lecture.

Something similar happened to me in a general engineering curriculum where our
introduction to programming was in C on some old unix machines that were
already already very obsolete (as of end of 90s), with no more IDE or debugger
than the equivalent of notepad and debug by printf. I thought it was
interesting but too tedious for my taste (I had never heard of IDEs and
debuggers).

It's only years later that I went back to programming, from higher level
languages, and progressively making my way into more sophisticated / lower
level languages.

You don't teach kids math by starting with topology. Most 1st year university
students will have never programmed in their life (particularly if all they
dealt in their life was smartphones and tablets).

~~~
golergka
> Most 1st year university students will have never programmed in their life

What? That's completely untypical for me - I would expect that in a university
with decent admission competition (don't know how these things work in US
exactly) students that get in know at least a couple of high-level programming
languages in addition to taking part in programming competition and general
geekiness like brainfuck.

~~~
joppy
The point of university is to learn, not to already know the course content by
the time you get there. Plenty of high-school students may not have taken any
computer science subjects during school, but may wish to get a degree in
computer science.

Universities with decent admission competition value well-rounded, high-
achieving students. Such students are involved in a lot of co-curricular
activities, may take many subjects, and have broad interests. It's perfectly
reasonable to expect that they simply never had the time to learn multiple
programming languages and compete in programming competitions, in addition to
whatever else they do.

------
writepub
Most people coding in C don't hang out on HN or SO. They are typically
electrical engineers working for companies selling hardware. They tend to be
less web savvy than the average CS/programmer types, but they're the ones
building the guts of the infrastructure that runs the world.

C isn't going anywhere, even in 10 years. People keep floating Rust and the
like, but most targets for C have 16KB program space, and about that much in
RAM budget. The C standard library itself is opportunistically linked on these
platforms.

The dependencies required for Rust, or even C++, are larger than the code
space of 90% of the microcontrollers in your car

~~~
steveklabnik
The smallest binary rustc can produce is 148 bytes. You can get small binaries
if that’s something you care about.

------
z92
If you intend to write extension for Python, Ruby, PHP, Lua, Node or most of
any high level language, you need to write it in C.

Want to build a library that can be used in any of the high level languages?
Write it in C and provide binding.

A library code written in PHP can't be used by Haskell. Not without a big
overhead. Or vice versa. Write it in C and your are done.

These are where C still comes handy.

~~~
blub
Unless I'm missing something, any language offering a C FFI can be used to
provide interoperability.

~~~
humanrebar
Depends on what you are doing. You often need to pull in the other language's
runtime while libc is typically already in use. You also have to be careful
about ABI details like string representations, concurrency, and threading
features.

------
tomcam
> There’s a lot of reading material out there. For the basics, I still
> recommend that students purchase K&R. People say good things about C
> Programming: A Modern Approach; I’ve only skimmed it.

This early quote filled me with dread. The article fulfilled that dread. IMHO
K&R was a classic book but C has changed far too much for that to be of
service to students, who would have to unlearn as much as they learn.

Then the author, a college teacher, offhandedly mentions another outdated book
as if to recommend it but admits no firsthand knowledge of it. A serious
programming student taking these recommendations has just spent a hundred
bucks or so and a great deal of precious study time on material that will
derail them from their studies with no benefit at all.

~~~
docbrown
Is there any updated texts that you or anyone else would recommend for people
new to C?

~~~
MarvelousWololo
I'd love to know this as well.

------
raymond_goo
I still have my university-library-xeroxed pages from Expert C Programming
from 20 years ago... Seems like I got lucky since it was the second and only
other C book I ever read on C, apart from K&R of course...

------
dang
Discussed at the time:
[https://news.ycombinator.com/item?id=11668396](https://news.ycombinator.com/item?id=11668396)

------
arendtio
> [...] on the (thankfully excellent) collection of tools that is available
> for helping us develop good [...]

That statement could also have been made by someone teaching Javascript in
2018 :D

Kinda funny how we 'fix' high-level languages by augmenting them with tools.

------
paedupeax
I wonder what his views are on using an IDE vs. using a plain text editor.
Because getting to know the tools (compiler, build system) is important, I'd
go for the latter choice.

------
kita99
What books do you recommend for a newbie to C?

------
mayank005
good news

------
throwaway487548
> C is probably a poor first or second language.

What does he mean by "probably"? How could anyone in PL and teaching community
ignore _decades_ of research and development of teaching materials in Scheme
and Standard ML?

Scheme (Racket) should be the first language. Standard ML or Haskell - the
second. One will tap into two distinct whole sub-cultures (US and British
respectively).

Also this way of teaching C as a specialized implementation language which
must be used together with special tools is the right way. It is useless to
teach C without or prior to machine architectures and assembler language
basics.

C is by no means a general purpose language, even when the industry is using
it this way and should be taught only as part of specialization in systems
programming.

------
Insanity
I kind of want to say it's important for programmers to have some knowledge of
C but frankly I'm not sure that's true anymore.

There's only been once case in which I really needed C (because I was
programming for a system from the 90s and I only could get C running with the
tools I had).

As others have said in this thread, it might be useful for you if you end up
in embedded devices or other areas of development, but it won't help you for
the bulk of applications written in Java / Python or some other higher-level
languages.

------
blub
The biggest issue C has is that there's no good answer to the second big
question.

No matter how you slice and dice C, its highest abstractions are functions,
structs and pointers and all of them can fail catastrophically at each and
every point of use.

One can't even add two numbers or read from a variable in C without the
possibility of triggering undefined behaviour. And there's nothing that will
rescue you from that possibility except paying attention, which is something
us humans can be pretty bad at.

When using C, one is setting themselves up for failure, which already hints at
the answer to the first big question - no. Go, Rust and C++ can do everything
C does in a safer way.

