Hacker News new | comments | show | ask | jobs | submit login
Learn C Programming with Open-Source Books (ossblog.org)
340 points by vinny12 on Feb 6, 2017 | hide | past | web | favorite | 49 comments



One of the greatest non-free books, IMO, is 21st Century C and I cannot recommend it enough.

http://shop.oreilly.com/product/0636920033677.do


Working my way through it now, in my efforts to re-learn C. Besides the treatment of modern standard C, I like that it treats the C development and distribution environment as a first class subject.


This looks like a great resource. Interesting that the author says this book is partly for "application devs".

As a JavaScript dev, learning C has always had a certain appeal. However, anytime I start to dive in, there's this nagging voice in the back of my head telling me that I'm wasting my time as I will never use what I'm learning.

To any devs coming from higher level languages, have you found learning C useful in any practical sense? Or has your exploration of C been more "for fun"?


Yeah I really liked 21st Century C as well.

Just a FYI for anyone looking to get it - make sure you get the latest edition (currently 2nd edition) as the first had a lot of issues which they fixed in the 2nd edition thanks to good feedback.


I liked comment about manual memory management ("This memory model is why Jesus weeps when he has to code in C") and on page 151 in features table "Jesus weeps", made me smile.


I just read it myself. For someone new to C, it was great to find a concise source of info on things in the modern C ecosystem and toolchain. For example, I appreciated the chapters on Autotools and Python bindings. Of course this info is available elsewhere, but it's great to have a short guide that covers the basics.

One warning on the Python chapter, though. It is Python 2. But, it was a nice intro and got me reading the Python3 C API docs to see what changed.


One thing I always not see people recommending is what small open source projects I can study or do while or after reading these books. Like for web development, people try to implement a small todo, blogging software. For someone coming from higher level languages like Python, Ruby, studying low level library is very tough to grasp. Having small but a proper project in itself will be helpful. I have heard praises about Redis and SQLite, but for beginners, they are quite big.

So any suggestions?


A personal preference of mine is to write a simple http server with GET and a few error codes implemented. It usually covers networking, file IO, exceptions in some cases, multi-threading, string parsing, etc. If it feels like too much then you can always start off with a smaller subset of features.


Threads? That is not for beginners.However, your idea is great last summer I was told to code such in an interview that with a hook to Lisp. I learnt so much even though I failed the interview.


Presently coming from Python to C, I'm trying to figure this out myself. One issue that occurs to me is that someone coming from a higher level language like Python or Ruby might have to re-calibrate what they consider 'small'. Since C itself is a smaller, lower level language, functionality that might be small and simple in say, Python, is probably going to be bigger and more complex in C. There are no lists, tuples, dictionaries, strings or sort functions from a batteries-included standard library in native C. If you want such, well, here's your ints chars and pointers, have fun implementing them yourself. (That's not intended as a slam against C)

As for suggestions, all of the following are guesses because of my own n00b status with C. That said:

The runtime of the higher-level language of your choice. If you already know Python well, looking under the hood and seeing the C code that actually implements all the convenient and useful bits may well be instructive.

Rsync. I was able to get some small understanding of how it worked by browsing the source even though I knew hardly any C at the time.

Postfix. I don't think is a small project, but I have heard it spoken well of from a security standpoint -- in part because it is actually several small programs/modules that specialize in one task. Those individual binaries/modules might be comprehensible on their own.


The Python/C API is pretty straightforward and can be a good intro since you'll see how some of the Python types are represented with the curtains pulled back. Try porting a small module of your own from Python to C. Then refactor it so it can be used in a stand-alone C program with just a few wrappers for the Python API. Then try plugging it into a C program instead.


Not quite a direct answer, but book(s) missing from op is:

http://aosabook.org/en/index.html

("Architecture of open source applications") and siblings.

I'd say reading the section on "git" there, and then having a look at the git source - or "nginx" and looking at the source - etc - might be one place to start.

Other than that, off the top of my head (suggestions from a hobbist): sqlite, the samba lightning db lmdb, the new openbsd daemons like httpd, opensmtpd, and the NaCl crypto library.

Hopefully more battle-hardened c-programmers can comment/add to the list.

[ed: and seeing rsync mentioned below, I recalled spiped along with a handful of other utilities by Colin Percival (former FreeBSD Security Officer, founder of tarsnap and active hn-er) http://www.tarsnap.com/spiped.html ]


If you're going to try to learn C by looking at any of my code, I highly recommend that you pick spiped for that purpose. Tarsnap is built around libarchive, which is good code but much bigger and less coherently organized; scrypt and kivaloo sacrifice clarity for performance in many places.

But spiped is just 6500 lines of code, of which 4300 is segregated library code; a novice C programmer should be able to start by treating those as black boxes and read through the rest of the code to get a clear sense of how the entire program works -- something which is almost impossible for a program as large as even OpenBSD's minimalist httpd.

And reading spiped will expose you to a lot of the concepts which experienced C developers take for granted -- non-blocking network I/O and callbacks, threads, "extending" the language by creating more sophisticated data structures, workarounds for non-POSIX platforms, etc.



Great applauses for not recommending the "indisputable classic" from K&R. The latter is really an introductory text that presents the features of the language in a chaotic manner and introduces some very nasty 1970s styles of coding.


Having just picked up this very book I appreciate the caution, however I will point out that K&R's tome - while perhaps not the definitive guide to style, is an approachable, brief overview of the C language for those of us who took it in high-school prior to C99 and have since been re-exposed to C through Arduino IDE and OpenSCAD.

The O'reily cow book covers C99 and is a good companion.


K&R gets so much hell, but it's a good, raw back to basics text. It deserves a place on the shelf beside the ARRL Ham Radio License Manual, or Wheelock's Latin, or Lyman's Guide to Reloading, or The Joy of Cooking, or the Elements of Style. It's the programming book for Boy Scouts, a crude, but essential Swiss Army Knife --the great programming book for the post-Apocalypse.

Also all of these are open source submissions.


Is there a list of this very nasty 1970s styles of coding somewhere? Is it mainly that it is outdated and doesn't describe the lastest C standards?


It is bad not only because it predates C99, but also because virtually any example consists of a couple of global variables/fixed-size arrays, a couple of badly named functions which operate on the globals and use some very "descriptive" names of the local variables. This book was born in an era when the modern understanding of "good code" was barely honored at all.


"Relying too heavily on external variables is fraught with peril since it leads to programs whose data connections are not at all obvious" - k&r, ch. 1

Who are these Kernighan and Ritchie guys? They obviously just don't understand "good code", terrible book!


People pick up on what you do, including supplied examples, not what you say.

(And I say this as someone who likes K&R.)


Take, for example, the declaration parsing example and honestly tell me that this isn't crappy code by any modern standard:

    enum { NAME, PARENS, BRACKETS };
    void dcl(void);
    void dirdcl(void);
    int gettoken(void);
    int tokentype;
    char token[MAXTOKEN];
    char name[MAXTOKEN];
    char datatype[MAXTOKEN]; /* data type = char, int, etc. */
    char out[1000];

    main()  /* convert declaration to words */
    {
        while (gettoken() != EOF) {   /* 1st token on line */
            strcpy(datatype, token);  /* is the datatype */
            out[0] = '\0';
            dcl();       /* parse rest of line */
            if (tokentype != '\n')
                printf("syntax error\n");
            printf("%s: %s %s\n", name, out, datatype);
        }
        return 0; 
    }


Pg 124 from 2nd edition where this code is pulled (emphasis mine):

"[T]he programs are intended to be illustrative, not bullet-proof, there are significant restrictions on dcl."

In context this code illustrates the points they're trying to convey about complicated declarations quite well and is a precursor to understanding typedef later in the book.

Also, you left the nice inline comments off the variable declaration block.


I would like to see where typedef could have been used?


"Modern standard" or not, I find this piece of code highly readable, and, in general, very good for what it does, at the level (of simplicity, perhaps even "primitivism") at which it was intended to do that.


This piece of code is crap - it's not functional, keeps implicit state.


Not all quality code is functional.


Could someone point out the craps in the code ? I only noticed excess use of global variables , and out array(can't figure out why it was index only at zero)


would you also criticize newton's principia mathematica because he expressed the concept of infinitesimals using geometry instead of using liebniz's or lagrange's arguably clearer notations?

K&R was written in a different time, where computing had stricter (but not really different) constraints, but it's still arguably the clearest expositions of the language around.

considering computing hasn't changed that much since K&R was written, it's unlikely your idea of good code differs much from what was done 40 years ago. for example, functional programming, which is the popular dogma today, was invented around that time.

take the good (it's not hard to find in a book like K&R), discard the (perceived) bad, and move on with your life.


Actually - it does mention it, but at the very bottom with a short explanation and a link. I have a first edition of the book, so I agree with your statement - but do the later editions (or the latest for that matter) still carry the ugliness? Perhaps they do...?


There are no later editions other than the 2nd, from 1988. Draw your own conclusions...

(I'm very fond of the book as a historical artifact, btw)


As this list is of open source books, no...K&R C shouldn't be on there.


Is there a former ;-)


Non-native speaker here :-)



Scrolling randomly through the document my eyes almost popped when I saw [Level 3, Chapter 16: Performance]:

  A pointer to a collection of objects of unknown number. These functions
  should use the VLA notation:
 
      void func(size_t n, double a[n]);
I had no idea this was possible. Do compilers actually do anything with this information or is it just informative?

EDIT: I didn't get a warning out of gcc

  #include <stddef.h>
 
  int last(size_t n, int a[n]) {
    return a[n-1];
  }
 
  int main() {
    int a[] = {0, 1, 2, 3, 4};
    size_t siz = sizeof(a) / sizeof(a[0]);
    return last(siz+1, a);
  }
Compile:

  $ cc --version
  cc (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4
  Copyright (C) 2013 Free Software Foundation, Inc.
  This is free software; see the source for copying conditions.  There is NO
  warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

  $ cc -Wall -Wextra -std=c11 staticarr.c -o staticarr && ./staticarr ; echo $?
  254
clang 3.8 warns about differing things:

  $ clang-3.8 -Weverything -std=c11 staticarr.c -o staticarr && ./staticarr ; echo $?
  staticarr.c:3:25: warning: variable length array used [-Wvla]
  int last(size_t n, int a[n]) {
                          ^
  staticarr.c:3:5: warning: no previous prototype for function 'last' [-Wmissing-prototypes]
  int last(size_t n, int a[n]) {
      ^
  2 warnings generated.
Still, it's a neat idea from a documentation point of view, and GNU-like compilers seem to accept it.

A bit before is more explanation of on the arr[static ?] notation. I was aware of this and usually prefer to use (Clang/GCC) function annotations to indicate NULL-ness of pointers and such, but I see the advantage in some situations. I don't agree with everything in the document, but it contains a lot of cool things.


I think it's worth clarifying that arrays declared in parameter lists are simply just pointers. It's 100% syntactic sugar. So the `int a[n]` is simply treated as `int * a`, and the value inside of the `[]` is ignored completely. This leads to the weird situation that you declared it as `int a[n]`, but `sizeof(a)` just gives the size of a pointer, not the size of the array.

The only special case is `int a[static n]`, which does tell the compiler that `a` has at-least `n` entries. But `a` is still just a pointer in this instance, so `sizeof(a)` still gives the size of a pointer.

Personally, I'd recommend avoiding the syntax purely because of the `sizeof` issue, but its up to you.


VLAs were added in C99, but not universally adopted (particularly by embedded systems compilers, for obvious reasons), and then made optional in C11.


You're completely right, but I think it's worth clarifying that VLA notation in parameter lists, and actual VLAs are two completely different things. The example he showed doesn't actually use a VLA, it just looks like it does.


I don't see an obvious reason - that's all information that's available on compile-time, there should be no additional run-time cost - or what are you implying?


VLA allows for run-time size determination, not compile time


It's already in the list.


Oops just woke up


That link did not work.

From the article though: http://icube-icps.unistra.fr/img_auth.php/d/db/ModernC.pdf


The http://c-faq.com/ is a very good resource too.


Not a story that interests me, but this is a wonderful blog! I'm definitely following this.


Maybe I am not seeing the same articles as you.

- 5 best open source board games to play online.

- 9 ASCII games you'll want to play again.

- 3 open source python shells.

So basically just a blog that creates lists. We see this a bit too often on YouTube. I am not sure we need more boingboing/BuzzFeed style of blog spam..


All gems!


Are there some recommended book on




Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact

Search: