[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)