[HN Gopher] Teaching C (2016)
       ___________________________________________________________________
        
       Teaching C (2016)
        
       Author : arkj
       Score  : 139 points
       Date   : 2022-09-11 11:47 UTC (11 hours ago)
        
 (HTM) web link (blog.regehr.org)
 (TXT) w3m dump (blog.regehr.org)
        
       | jvanderbot wrote:
       | We're 4 years away from the time when TFA predicts no new
       | projects will begin with C.
       | 
       | I wonder how the claim holds up? Certainly not well in the
       | embedded space, and Rust mainline kernel development seems still
       | a few years away at least.
       | 
       | I'd argue there's some transition in space fsw to c++, but that's
       | not really significantly different than C+classes, since most c++
       | features and std:: are not allowed.
       | 
       | When does automotive, iot, and other spaces anticipate
       | tansitioning?
        
         | elteto wrote:
         | FWIW I've seen space FSW instances where both std:: was allowed
         | and forbidden. One instance was soft real-time FSW running on a
         | customized Linux. Most (sane) C++ was allowed, exceptions were
         | not disabled, just disallowed, std:: was allowed during
         | initialization, but not past that, memory allocation was only
         | allowed during initialization as well, although a stray
         | allocation at runtime was only fatal in testing, not during
         | flight. It was logged in both cases and considered a critical
         | issue. PR reviews had strict checklist rules regarding allowed
         | syntax/features. It was very productive using all of the
         | necessary C++ features, within reason, to write code.
        
         | pjmlp wrote:
         | Automotive standards like AUTOSAR have been using C++ for quite
         | some time and now are looking into Rust as well.
         | 
         | https://www.autosar.org/news-events/details/autosar-investig...
         | 
         | Note that MISRA is also adopting AUTOSAR on their standards.
        
         | macintux wrote:
         | To be fair to the author, the claim is that it's _at least_ a
         | decade away.
        
         | svnpenn wrote:
         | > We're 4 years away from the time when TFA predicts no new
         | projects will begin with C.
         | 
         | True, but AFT gives us at least 8 years.
        
         | arinlen wrote:
         | > _We 're 4 years away from the time when TFA predicts no new
         | projects will begin with C._
         | 
         | I'm not sure if this is representative, but most of my recent
         | FLOSS projects have all been C89 libraries.
         | 
         | The rationale is that it's trivial to add C bindings in any
         | language, it's extremely fast to build, and it runs everywhere.
        
           | andrewmcwatters wrote:
           | This is the exact reason I build and ship using C89.
        
           | chrchang523 wrote:
           | In your case, how much compatibility is lost from using C99
           | over C89? (I'm comfortable with C99 and still write some low-
           | level multiplatform code in it, but losing the ability to
           | declare variables where they're first used is a bridge too
           | far for me...)
        
             | SubjectToChange wrote:
             | Just for reference, projects like SQLite use C99.
             | 
             | IMO, targeting C89 is only warranted when you know for a
             | fact it's needed. After all, not only is C99 a good
             | improvement but toolchains stuck on C89 are not the type of
             | toolchain I'd want to support.
        
             | arinlen wrote:
             | > _In your case, how much compatibility is lost from using
             | C99 over C89?_
             | 
             | Until somewhat recently C89 was the latest version of C
             | that was supported by the MSVC compiler. Support for C99
             | was always terribly broken and Microsoft chose to claim it
             | did supported C99 but without supporting mandatory
             | features, which meant they did not in fact supported C99.
             | 
             | This sad state of affairs only changed significantly in
             | 2020, with a lowkey announcement.
             | 
             | https://devblogs.microsoft.com/cppblog/c11-and-c17-standard
             | -...
        
       | bowsamic wrote:
       | I have nothing to say other than that I love C and I will always
       | love C. That love affair began when I first walked through the
       | tutorial chapter of K&R, and it never died down. I'm not sure
       | what it is, but it is just beautiful to me.
        
       | projektfu wrote:
       | How strange, I was going to respond to a question about this
       | code:
       | 
       | https://git.musl-libc.org/cgit/musl/tree/src/string/memchr.c
       | 
       | and the user has completely disappeared along with their
       | comment/question.
       | 
       | Anyhow, you can think about the __GNUC__ part as an attempt to
       | fast-forward the loop by testing size_t-length chunks for the
       | character by XOR-ing the chunk with a repeated string of that
       | character. The first loop aligns the pointer for the fast-
       | forward. The final loop is then used to test the unaligned part,
       | which when not using __GNUC__, would be the complete loop.
       | 
       | I felt the need to answer because I'd done the work.
        
       | DrNosferatu wrote:
       | What about the Deitel books?
        
       | hnthrowaway0315 wrote:
       | Just curious, is there a C system programming book that gradually
       | feeds the readers with progressive (in difficulty) sys
       | programming projects? I red CSAPP and that is a good one, but the
       | scope of the projects is a bit limited.
        
         | rramadass wrote:
         | You may find _UNIX Systems Programming: Communication,
         | Concurrency and Threads by Kay Robbins & Steven Robbins_
         | useful.
        
       | enahs-sf wrote:
       | As I think about teaching my son programming, I think I would
       | start with C and assembly because although it's super low level,
       | it gives you a fundamental understanding of how the machine
       | works. The debugging and problem solving skills these languages
       | impart will also be invaluable.
        
         | SubjectToChange wrote:
         | >... it gives you a fundamental understanding of how the
         | machine works.
         | 
         | ISO/GNU C is unfit for programming classes of devices as
         | ubiquitous as smartphones, or virtually any type of SoC. There
         | is a reason CUDA/OpenCL/ROCm/SYCL exist and why they can't be
         | programmed like usual C if you want performance.
        
       | mannykannot wrote:
       | "The other way of teaching undefined behavior, by looking at its
       | consequences, is something that we should spend a bit of time on,
       | but it requires a different kind of thinking and we probably
       | won't expect the majority of students to pick up on all the
       | subtleties -- _even seasoned professional C programmers are often
       | unaware of these._ "
       | 
       | I feel that last phrase exemplifies why this should be given
       | quite a lot of attention. It is also the sort of thing that will
       | lead a student to a deeper insight into the language and how it
       | differs from the other procedural languages that they are likely
       | to already be familiar with (the same can be said for memory
       | management, BTW.)
       | 
       | Such a course might be something of a grind, but if so, it would
       | inculcate the right sort of attitude for programming competently
       | in C!
       | 
       | For dessert, take a quick look at some Obfuscated C winners.
        
       | blinkingled wrote:
       | RMS recently released reference manual for GNU C - I am finding
       | it to be direct and succinct.
       | 
       | Edit: I used to teach C to a group of undergrads and one question
       | that came up often was around the special significance of the
       | main function and order of definition of functions.
       | 
       | The RMS book addresses this very succinctly -
       | Every C program is started by running the function named main.
       | Therefore, the example program defines a function named main to
       | provide a way to start it. Whatever that function does is what
       | the program does. The main function is the first one called when
       | the program runs, but it doesn't come first in the example code.
       | The order of the function definitions in the source code makes no
       | difference to the program's meaning.
       | 
       | https://lists.gnu.org/archive/html/info-gnu/2022-09/msg00005...
       | If you understand basic concepts of programming but know nothing
       | about C, you can read this manual sequentially from the beginning
       | to learn the C language.
        
         | curious16 wrote:
         | Can anyone link me to the pdf directly. I don't find it on the
         | link above. I am stupid.
        
           | treeblah wrote:
           | There's no direct PDF, you have to build it yourself w/ TeX
           | by cloning the repo:                 git clone
           | https://git.savannah.gnu.org/git/c-intro-and-ref.git       cd
           | c-intro-and-ref/       make c.pdf
        
           | 1vuio0pswjnm7 wrote:
           | I am stupid, too. I generally do not use git(1). I wrote a
           | short script to download the manual as a single 639K text
           | file. I do not use a GUI or mouse so this makes it easier for
           | me to work with code snippets. I also reformat the text to
           | match personal preferences. Here is an example script using
           | popular curl program to make the HTTP requests.
           | # requirements: curl, links, perl, texinfo (Linux), texi2html
           | (BSD)              #!/bin/sh         set -v;
           | x0=c-intro-and-ref.git;
           | x1=https://git.savannah.nongnu.org/cgit/;         test -d
           | $x0||mkdir $x0;cd $x0||exit;         for x2 in Makefile
           | c.texi cpp.texi fdl.texi fp.texi texinfo.tex;do         echo
           | url=$x1$x0/plain/$x2;         echo output=$x2;         echo
           | user-agent=\"\";         done|curl -K/dev/stdin -s;
           | case $(uname) in :)         ;;*BSD) texi2html --no-headers
           | --no-split --html c.texi         ;;Linux) makeinfo --no-
           | headers --no-split --html c.texi         esac;         #
           | personal preference for ~15-inch screen: 4 space indent,
           | 60-70 max chars per line         links -width 70 -dump .html
           | \         |sed '/^ *Link:/d;/^ *\*/s/\*//;s/^/    /;/Jump to:
           | /{N;N;d;}' > c.txt;         exec less c.txt;
        
           | 6581 wrote:
           | There is no PDF.
        
           | veqq wrote:
           | There is no pdf. Following the chain, you get to a git you
           | can download. But this guy has a tar of it as a single html
           | page.
           | 
           | https://forums.linuxmint.com/viewtopic.php?t=381284
        
           | Snarwin wrote:
           | Someone has uploaded a PDF to github, here:
           | 
           | https://github.com/VernonGrant/gnu-c-language-manual
        
         | xphos wrote:
         | You know I can think of a handful of examples where main is not
         | true. C to my understanding does not define that the
         | implementation does and think this is kind of exactly what the
         | other is saying that this implied assumptions lead to issues in
         | C development. This albeit is an extremely superficial
         | assumption that isn't in 99% of cases going to matter except in
         | of course security and embedded systems
         | 
         | I think the biggest issue with C is that it's taught as the
         | programs you are building is foundation of everything while
         | brushing under the rug that in also all course work you are not
         | build C on bare metal you almost always are building on on OS
         | which runs an implemented hardware which are extremely
         | important. But by teaching your building on this all powerful
         | language makes overconfident programmers. I've known so many
         | developers who jump the gun and think they are write what will
         | happen on the computer without understanding how high in the
         | clouds they normally are.
        
         | jalino23 wrote:
         | thank you for this!
        
         | WalterBright wrote:
         | > The order of the function definitions in the source code
         | makes no difference to the program's meaning.
         | 
         | Not exactly true. Consider:                   #include
         | <stdio.h>         int foo(double d) { return (int)d; }
         | int main() { printf("%d\n", foo(3)); return 0; }         /*int
         | foo(double d) { return (int)d; }*/
         | 
         | This prints different results depending on whether `foo` is
         | defined before `main` or after `main`. This is caused by
         | implicit function declaration.
         | 
         | gcc will warn about this if the -std=c11 switch is thrown, but
         | by default it will compile without error or warning.
        
           | stephencanon wrote:
           | Strictly speaking he's correct as "definition" is distinct
           | from "declaration", but yeah.
        
             | WalterBright wrote:
             | I wrote definitions in the example, and the order
             | dependence is clear.
        
               | kragen wrote:
               | But if you _declare_ the foo function before main, it
               | works correctly regardless of where it 's _defined_. The
               | definition just has the effect of also declaring it,
               | which is what makes the difference.
               | 
               | (Of course _you_ know all this much better than I do, but
               | someone younger reading this thread might be mystified.)
        
               | WalterBright wrote:
               | That wasn't the statement in the book, though. The thing
               | is, this is a serious misfeature which isn't present in
               | other languages, and can cause bizarre problems to the
               | poor newbie user.
               | 
               | This order dependency is why C source code tends to be
               | written bottom-up, rather than the more natural top-down.
        
           | blinkingled wrote:
           | gcc 12.2 on Arch warns about it with no switches - sure RMS
           | did not put a disclaimer on his claim but one can reasonably
           | assume he meant if you write correct C the order will not
           | matter. (Btw I have a feeling every statement about C would
           | need to carry that disclaimer lol - main will be called if
           | you did not LD_PRELOAD a .so that caused premature exit in
           | init function etc.)                   gcc /tmp/testf.c
           | /tmp/testf.c: In function 'main':         /tmp/testf.c:4:18:
           | warning: implicit declaration of function 'foo' [-Wimplicit-
           | function-declaration]         4 |   printf("%d\n", foo(3));
           | |                  ^~~
        
           | marcodiego wrote:
           | Here gcc (9.4.0) throws a warning if the first declaration is
           | commented and the second one uncommented, but it prints "0".
           | Care to explain why?
        
             | WalterBright wrote:
             | Because foo() gets implicitly declared as accepting int
             | arguments, when it actually accepts a double. The double
             | bits interpreted as an int are 0.
        
               | edflsafoiewq wrote:
               | On x64, foo(double) expects its argument in xmm0, but
               | foo(int) expects it in rdi. So the 3 passed in rdi is
               | ignored and it operates on whatever happened to be in
               | xmm0.
        
               | WalterBright wrote:
               | Yes, you're right. Thanks for the correction. I was
               | thinking of the Windows C ABI.
        
           | WalterBright wrote:
           | Amusingly, the ImportC compiler I wrote will produce the same
           | result regardless of the order, because it allows forward
           | references.
        
         | synergy20 wrote:
         | Would be nicer if RMS can add TOC on the PDF, to make
         | navigation _much_ easier.
        
         | [deleted]
        
       | CJefferson wrote:
       | Having taught C at University, I found the hardest bit being how
       | many "well, but..."s to give.
       | 
       | C feels like a very simple language, but there are lots of subtle
       | corners which probably don't need teaching at first.
       | 
       | On the other hand, I think it's important to hammer home
       | "undefined behaviour" early. There are too many guides that say
       | writing outside the bounds of an array "writes to memory outside
       | the array", which simply isn't true. It might write, it might
       | not, who knows, undefined behaviour means all bets are off.
       | 
       | In general I feel a lot of practical teaching of C is teaching
       | about undefined behaviour, which is something many other
       | languages (Java, Python, Haskell, Rust), either don't have, or
       | where they do beginners won't stumble across it.
        
       | bitwize wrote:
       | It's high time we declare C "unsafe at any speed" and cease
       | teaching it to every student. Only those who really need it
       | (legacy C codebase, microcontroller with a toolchain that doesn't
       | yet support Rust) need to learn it.
        
         | wudangmonk wrote:
         | I completely agree. Rust exists already so I do not understand
         | why all the other languages need to continue existing. Only
         | those that use Rust can be considered to be a good person since
         | using Rust is the morally responsible thing to do.
         | 
         | The question then becomes, why do we want more evil people in
         | the world?. Does that make any sense? because that's exactly
         | what you get when you don't use Rust.
        
           | zbird wrote:
           | Rust doesn't even have a formal specification at this time.
           | Technically speaking, everything in Rust is undefined
           | behaviour. That's a hard sell for, e.g., people writing
           | safety-critical systems.
           | 
           | Another problem recently was that compiling Rust required
           | downloading a binary blob from Mozilla. That's a no-go for
           | many projects.
        
             | pjmlp wrote:
             | AUTOSAR is looking into it, while Ada Core is collaborating
             | with Ferrous Systems to bring Rust to the kind of clients
             | that usually use Ada.
             | 
             | Meanwhile Microsoft has finally acknowledged picking C for
             | Azure Sphere was a bad idea for its overall security story,
             | and is now adding Rust support.
        
         | Kamq wrote:
         | C is unsafe. That's kind of the point of it.
         | 
         | But just because it's unsafe doesn't mean it should never be
         | used.
        
           | pjmlp wrote:
           | Its use should be considered to the same extent as a macro
           | assembler.
        
         | lionkor wrote:
         | How do you tell apart a student that will later work on a
         | legacy C codebase from one that won't?
        
         | absolut-dolt wrote:
         | Imagine being this drunk on the kool-aid.
         | 
         | Just telling on yourself, "I can't write software without
         | training wheels", "I couldn't be bothered to learn how pointers
         | work", so flagrantly.
         | 
         | Rust is unspecified, lacks real battle testing, and lacks any
         | substantial track record.
         | 
         | Comparisons to C are comical, and discussing Rust as being a C
         | replacement as if it were a forgone conclusion is just... I
         | mean I can't think of any way to phrase this that won't result
         | in a ban - so use your imagination.
         | 
         | Rust is probably a fine language. A lot of y'all down the
         | rabbit hole need a reality check though.
        
           | pjmlp wrote:
           | Powering VSCode search engine, AWS Fargate infrastructure,
           | ChromeOS and Android hypervisor infrastructure, Azure IoT,
           | Firefox rendering engine, Android Bluetooth stack ....
        
       | shadowofneptune wrote:
       | _C Programming: A Modern Approach_ was my first introduction to
       | programming outside of writing a few python scripts (didn 't know
       | I could define my own functions, for example). With just it and
       | MVSC I was able to pick up a lot of the general concepts and
       | practices, Last project I made while studying the book was a
       | clock for decimal time and French Republican dates in ncurses.
       | This was only back in 2020, so it still is relevant.
        
       | commandersaki wrote:
       | Also worth teaching: -fno-strict-aliasing.
        
         | einpoklum wrote:
         | I disagree. That is, when teaching C, I never gave examples
         | avoiding any aliasing, and if it somehow came up, I advised
         | against it. But I don't think it's a good idea to invest
         | teaching time in compiler options regarding aliasing; it's too
         | specific for an introductory C course.
        
         | synergy20 wrote:
         | fully agree, use strict-aliasing only after profiling and on
         | your bottleneck code, if necessary, otherwise, just use no-
         | strict-aliasing(linux kernel uses it too)
        
           | astrange wrote:
           | `-fno-strict-aliasing` is even less formally defined than C
           | itself is, so I don't think it's a good tool, you're just
           | hoping it works for your program and not actually checking.
           | UBSan/ASan cleanliness is a better goal.
        
         | lifthrasiir wrote:
         | There is a comment mentioning this. I do have a somewhat
         | different view that you should minimize the number of
         | "reinterpreting" casts (stealing the C++ terminology) in
         | general, which is often ill-advised at the first place. This
         | practice frequently eliminates the need for -fno-strict-
         | aliasing.
        
       | macintux wrote:
       | Not only an insightful post, but also a fair number of
       | interesting comments.
       | 
       | A couple of resources I found in the comments:
       | 
       | * A short list of safety rules for C:
       | https://en.wikipedia.org/wiki/The_Power_of_10:_Rules_for_Dev...
       | 
       | * A much longer document, 42 rules for coding in C and C++:
       | https://pvs-studio.com/en/blog/posts/cpp/0391/
       | 
       | Update: also, a 210-comment thread from 2018:
       | https://news.ycombinator.com/item?id=18334476
        
       | bluetomcat wrote:
       | C should be taught like any other language. One should understand
       | the historical context in which a language was born and why it
       | gained popularity. A lot of "vintage" C code is indeed bad
       | because elementary software engineering principles were not
       | widely understood back then. Pascal code of the same vintage
       | isn't significantly better, either. We've walked a way in
       | collectively understanding the importance of modularity, cohesion
       | and coupling and balancing complexity, and that smart isn't
       | always better in the long run.
        
         | qsort wrote:
         | I slightly disagree.
         | 
         | C still is, and will continue to be for the foreseeable future,
         | the lingua franca, the least common denominator. Acknowledging
         | how C comes with a very... interesting set of tradeoffs that
         | make it uniquely well-suited for certain purposes and at the
         | same time incredibly dangerous is a worthwhile proposition if
         | one is aiming to truly understand C development.
        
           | fallat wrote:
           | I think you meant "lowest common denominator" or "most common
           | denominator"...
        
             | qsort wrote:
             | Wikipedia has both forms:
             | https://en.wikipedia.org/wiki/Lowest_common_denominator
             | 
             | I'm not a native speaker - this is a genuine question -
             | does it sound weird to say "least common denominator"?
        
           | bluetomcat wrote:
           | True, but a good C course should explain exactly those
           | concepts and what kind of problems (in relation to assembly
           | and other HLLs) was C meant to solve back at the time.
           | 
           | I would highlight the following:
           | 
           | * Structured programming support, which means nested loops
           | and conditionals without a primary need for "goto" jumps,
           | enabling a sense of "depth" that is missing in the "flat"
           | world of assembly
           | 
           | * Expression-oriented syntax, meaning that operators (even
           | those having a side-effect) return a value of a certain type,
           | and can be nested, again enabling recursive program structure
           | versus a flattened one
           | 
           | * Global symbol allocation and resolution, which means that a
           | programmer uses names rather than addresses to refer to
           | global variables and functions
           | 
           | * Abstraction over function calling conventions, which
           | enables the programmer not to worry about function prologues
           | and epilogues and the order of pushing arguments on the stack
           | or in registers
           | 
           | * Automatic storage management, meaning that a function-scope
           | local variable is used by the programmer with its name and
           | the compiler decides whether to put it in a register or at a
           | certain offset in the stack frame
           | 
           | * Rudimentary integer-based type system that has the
           | distinction between a scalar and a fixed-size collection of
           | scalars laid-out sequentially (arrays), and special integers
           | called "pointers", supporting a different set of operations
           | (dereferencing to a certain type and adding or subtracting
           | other integers from them, without any safety guarantees
           | whatsoever)
           | 
           | Nothing more, nothing less. Not understanding these
           | foundations is the source of major pain.
        
             | shadowofneptune wrote:
             | The expression-ness of C really sets it apart from even its
             | successors. Declarations look like expressions, everything
             | does. You can see in C code from the time how heavily
             | expressions are used. C++, Java, etc. all added a bunch of
             | new keywords to the syntax that make it much more like
             | Pascal or other 'normal' languages. The culture of those
             | languages leans much more towards statements as well.
        
             | pjmlp wrote:
             | Macro Assemblers, which were never a thing in UNIX, do
             | offer support for structured programming, see MASM, TASM,
             | or going back to the days C was born, something like HLASM
             | on IBM mainframes.
             | 
             | Additionally many of the C features had already been sorted
             | out in JOVIAL, NEWP, PL/I, BLISS among others about a
             | decade before C was born.
             | 
             | C was solving the issues of UNIX v3 design, that is all.
             | 
             | Plenty of languages can be used to teach low level
             | programming concepts.
        
           | SubjectToChange wrote:
           | > C still is, and will continue to be for the foreseeable
           | future, the lingua franca, the least common denominator.
           | 
           | In the context of platform ABIs, sure. The widespread
           | stabilization and ossification of C ABIs is a boon for the
           | rest of the ecosystem but it's entirely at the expense of the
           | C language/stdlib. Hence the performance advantage of
           | projects like fmtlib.
           | 
           | Notwithstanding its ubiquity C is in many ways "The Sick Man
           | of Asia". Every major C compiler is written in C++ with
           | tooling heading the same way. The dominance of C++ in the
           | heterogeneous space has accelerated this trend and spread it
           | to many HPC libraries. Even foundational bits such as
           | Microsoft's UCRT or llvm-libc are written in C++.
           | 
           | On the current trajectory C will become the next Fortran,
           | i.e. a widely used language which is nonetheless unable to
           | support itself.
        
       | whateveracct wrote:
       | I learned C mostly on pen-and-paper exercises at my university.
       | Lots of drawing the stack and heap.
        
         | unwind wrote:
         | That is ... a bit weird, since C does not assume, recommend or
         | require that non-heap variables are implemented using a stack.
         | 
         | It's weird to teach a language while also ripping a hole in one
         | of its main abstractions and assuming stuff about how that
         | works, in my opinion.
        
           | turtledragonfly wrote:
           | Genuinely curious: do you know of any C implementations that
           | do not use a stack for such cases?
           | 
           | It seems so prevalent that locally-scoped variables are often
           | referred to as "stack variables" in casual conversation, but
           | I'm curious of cases where it's not true...
        
       | tamsaraas wrote:
       | C is an achievement that must be unlocked by programming in
       | different other high-level languages for years. Without this - C
       | will be pointless lecture.
        
       | [deleted]
        
       ___________________________________________________________________
       (page generated 2022-09-11 23:00 UTC)