[HN Gopher] Ask HN: How do I learn C properly?
       ___________________________________________________________________
        
       Ask HN: How do I learn C properly?
        
       I have 15+ years of experience in many languages: javascript,
       python, go, etc.  I can write C, but I'm not confident I'm doing it
       the right way. There are now decades of forums and blogs I can
       search through, but I'd love to have a single, clean, clear source
       of truth for recommendations on how to write C code.  I've started
       reading "Modern C" by Jens Gustedt. I'm not sure if this is the
       closest to a modern source of truth.  Note, I'd like my C code to
       work on Windows, which possibly restricts the "right way" to
       features provided by C89. But again, I'm not sure, the internet is
       super clear on this.  Thanks for the tips!
        
       Author : buchanae
       Score  : 89 points
       Date   : 2020-03-08 19:08 UTC (3 hours ago)
        
       | tedunangst wrote:
       | Radical suggestion: read the C standard.
        
         | kevindong wrote:
         | Asking someone to read a multi-hundred page standards document
         | just to learn the language is wholly unreasonable.
        
           | clarry wrote:
           | Well, OP asked for source of truth. Nothing comes as close as
           | the standard itself.
           | 
           | Honestly, I think any programmer writing C today should have
           | it around for reference. And yeah you kinda need to read it
           | too, or you won't be able to refer much.
           | 
           | That said, no need to read it cover to cover. There's stuff
           | one can earmark as being there but ignore until it's actually
           | needed (for example: the grammar and all the library
           | functions).
           | 
           | And speaking of _tedu_ , I would recommend to the OP that
           | they get in the habit of checking out the OpenBSD man pages
           | for libc functions.
        
             | sramsay wrote:
             | I actually have very few $200 PDFs lying around.
             | 
             | Do you really go purchase the standard documents from ISO?
             | Or does your employer? I'd love to have the actual standard
             | "around for reference," but 700-page technical documents
             | from ISO are not cheap.
        
               | clarry wrote:
               | The next best thing is the latest draft standards, which
               | are available online for free (and I always have them on
               | my laptop, PC, and personal server). Differences between
               | them and final official standard are not important.
               | Search for N1256, N1570. Or grab them here.
               | http://www.open-std.org/jtc1/sc22/wg14/www/standards
               | 
               | (There are more readable html versions floating about)
        
       | ajb wrote:
       | Read John Regehr's blog, eg https://blog.regehr.org/archives/213
       | 
       | Read "Who Says C is simple?": http://cil-
       | project.github.io/cil/doc/html/cil/
       | 
       | Take up a different language :-)
        
       | fhars wrote:
       | Essential reading:
       | 
       | https://blog.regehr.org/archives/213
       | 
       | http://blog.llvm.org/2011/05/what-every-c-programmer-should-...
        
         | jstimpfle wrote:
         | omg no. Stop obsessing about this dragon. I'm not sure I've
         | ever met it in my life (you know, other than segfaults from
         | NULL dereferences which are UB too).
        
           | saagarjha wrote:
           | How much C have you written, and how much has gone through a
           | high-performance optimizing compiler?
        
             | jstimpfle wrote:
             | I don't know. Quite a bit - maybe written 300K lines and
             | deleted > 200K lines. Most of it was compiled by gcc -O2 or
             | MSVC. I've never relied on vectorization or used a lot of
             | intrinsics, though.
        
       | Areading314 wrote:
       | I would recommend "Learn C the Hard Way" by Zed Shaw to get you
       | started for something practical, because it goes over how C is
       | written in the real world. Of course, situations will vary. The
       | original book about C by K&R is an excellent book too.
        
         | Paperweight wrote:
         | Zed makes it clear in that book that he hates C and doesn't use
         | it anymore due to its undefined behaviour.
        
       | WalterBright wrote:
       | I'd just type in the examples from K+R, try them out, and modify
       | them to do new things.
        
         | elliotec wrote:
         | Do this but get the answer book too, because it's easy to get
         | stuck in here.
        
         | wiredfool wrote:
         | K+R is pretty ancient.
        
           | WalterBright wrote:
           | So is C :-)
        
       | vocram wrote:
       | Becoming proficient in a language usually involves: - writing
       | code with it long enough, - collaborate in a project based on it,
       | - reading code other people wrote, - keep yourself up to date by
       | following the language evolution, - go more in depth in language
       | internals, compilers, etc...
       | 
       | I wrote C for 10+ years (mostly bare metal FW), yet I am still
       | amazed of how little I know about it. Recently for example I
       | learnt of all the things the dynamic linker does in Linux, how
       | symbols memory addresses are resolved at runtime using PLT, ....
       | 
       | The good point about C is that it can be used for very different
       | kind of projects, so the choices are a lot.
        
         | stiray wrote:
         | This was a pure satisfaction when I have first seen it :)
         | 
         | https://en.wikipedia.org/wiki/Duff%27s_device
        
       | 6c696e7578 wrote:
       | The C FAQ used to be a good place to start. Note, _used_ to be:
       | 
       | http://c-faq.com/
       | 
       | What did you want to do on Windows? I think this depends as much
       | on the compiler as the code.
        
       | [deleted]
        
       | makz wrote:
       | I'd say there's no proper way. Every project has its way of
       | writing C. With the use of macros, sometimes it looks a bit like
       | a DSL for every specific project.
       | 
       | My advice: think about what kind of software you want to write
       | and look for similar projects, libraries, or contribute with a
       | new module, functionality, adapt something to your needs...
        
         | pritovido wrote:
         | I would advice AVOID C macros at all cost. They are so weak and
         | hard to debug and problematic.
         | 
         | I write in several languages and read lots of C projects made
         | by others and find the affirmation hard to believe: C is so
         | simple that is very easy to read if the writer of code has a
         | minimum of competency.
         | 
         | You can say that of projects like C++, specially things like
         | C++11 that are languages by committee so complex that you can
         | affirm that every C++ programmer is different or find
         | programmers that could not understand each coder's code. Not so
         | with C.
         | 
         | That happens to me with C++ and lisp code. It takes a while for
         | me to understand what the author uses(or abuses) before being
         | able to understand the code. That does not happen with C code.
        
       | iRobbery wrote:
       | Besides all that is mentioned already to read or do. I would
       | suggest to try writing something you coded in python or go
       | previously in C.
        
       | pritovido wrote:
       | C is a very simple language. I have used just the official old
       | book to create a compiler for it:
       | 
       | https://www.amazon.com/Programming-Language-2nd-Brian-Kernig...
       | 
       | The best thing you can do is finding some open source code that
       | interest you, read it and write it.
       | 
       | For example, I write my own controllers for CNCs, and there are
       | lots of code for controlling stepper motors out there. I also
       | learned OpenGL and sockets this way long time ago.
       | 
       | On the other hand, C is a terrible language for any big project
       | unless you automate it some way.
       | 
       | I use mostly lisp in order to write C code automatically. C is
       | too low level for writing any substantial code. Lisp has things
       | like Macros(nothing to do with c macros) that can make you write
       | code 10x, to 50x faster easily.
        
         | kahlonel wrote:
         | > C is too low level for writing any substantial code.
         | 
         | Do people not realize that projects like Linux and pretty much
         | every car's ECU software (pretty "substantial" in my opinion)
         | is written in C before claiming this? I'm not saying these
         | software are 100% bug free, but this claim isn't accurate
         | either. You _can_ write substantial C code when you have a good
         | understanding of the tooling around it. Mere learning the
         | syntax isn't enough.
        
           | johnisgood wrote:
           | That, and I dislike the low-level vs high-level
           | differentiation. It is relative, and more of a spectrum, IMO,
           | and not that it is particularly useful anyway.
        
           | sramsay wrote:
           | I'm so tired of hearing about what you can't do in C and the
           | "only thing" it's good for. You can't write big systems. It's
           | only for embedded.
           | 
           | It's such a crackup, because the number of developers who
           | haven't got the memo on this is really staggering. How many
           | lines of code is GTK? Or Postgres? Or Nginx? Never mind
           | languages and operating systems.
           | 
           | I suppose Vim (~335,000 lines) or git (in the 200,000 range)
           | is not "large" in comparison to some things, but I suspect
           | that's actually the kind of number people think is "too big
           | for C."
           | 
           | People also seem not to realize that the reason that Python
           | library is so fast, is because it's actually wrapping C code.
           | And that code is very often not doing some frighteningly low-
           | level thing, but just doing ordinary stuff.
        
             | samatman wrote:
             | The "steel man" version of this argument is that, if you're
             | embarking on a new codebase which you have good reason to
             | expect will grow to be large, have a _very good_ reason to
             | write it in C, or use a more appropriate language.
             | 
             | There some reasons to do it, but fewer than there were when
             | most of the projects you've name-checked were started.
             | 
             | I'll skip the part where we review what the other options
             | are, this is HN, we've all seen that thread before.
        
               | acqq wrote:
               | Knowing how some big software systems lived through more
               | than a decade each, I'd claim that the less they used C++
               | and the more used C++ compilers to write a C-like code
               | they were _better_. The worst parts of the project were
               | exactly those that used the  "cool" C++ features.
               | 
               | C is much better for really long-lived projects than C++
               | is. C++ is a maintenance nightmare in comparison.
        
               | sramsay wrote:
               | I take your point about the age of some of these projects
               | (though it's not like there weren't any "more
               | appropriate" languages around when most of them started).
               | And I'll also admit to agreeing with the idea that choice
               | of language is nearly always a sociological matter before
               | it's a technical one.
               | 
               | But I'm not really arguing that C is the best choice for
               | large projects. I'm just pointing out the fact that many,
               | many people just completely ignore that advice. They are
               | ignoring that advice _today_ -- right now. With new
               | projects. And they 've "seen that thread before" too.
               | It's not _just_ legacy, or lack of awareness, or
               | whatever.
               | 
               | Maybe it comes down to what the "very good" reason
               | actually is. Because given the amount of C hacking going
               | on, I wonder if the "good reasons" we hear about nearly
               | every day on HN aren't the most important ones for the
               | quite vast number of people merrily hacking away in a
               | language that is now decades old.
        
             | pjmlp wrote:
             | As the CVE database proves, just because one can do it,
             | doesn't mean one should do it.
             | 
             | Liability can't come soon enough.
        
         | 3fe9a03ccd14ca5 wrote:
         | > _The best thing you can do is finding some open source code
         | that interest you, read it and write it._
         | 
         | Has reading source code in a language that's unfamiliar to you
         | shown to be of any real benefit to learning? It seems you need
         | at least a little bit of foundational experience with it before
         | your brain can even parse what you're seeing in a beneficial
         | way.
        
           | hombre_fatal wrote:
           | For me there's almost no wisdom to assimilate when reading
           | source code until I've given a fair shot at using the
           | language and experiencing its obstacles. Then seeing other
           | people overcome them is where almost all of the a-ha moments
           | are.
        
           | dandigangi wrote:
           | I'd tend to agree here also. I didn't start reading source
           | code until a couple years in because I couldn't really put it
           | to use. It becomes 10x more valuable when I was deep into my
           | career learning from the big shots.
           | 
           | It _can_ help no doubt but not sure that's the best way to
           | start. Especially with a language like C. It's not so
           | straight forward without some training or CS education.
        
             | clarry wrote:
             | > It becomes 10x more valuable when I was deep into my
             | career learning from the big shots.
             | 
             | Yeah well OP said they've 15+ years of experience so..
             | 
             | > Especially with a language like C. It's not so straight
             | forward without some training or CS education.
             | 
             | I agree with pritovido, when they say C is a very simple
             | language. Sure, it has grown its quirks and gotchas along
             | with some cruft (the kind of things you wouldn't learn
             | about in a CS curriculum anyway), but at its core it really
             | is very simple.
        
           | clarry wrote:
           | > Has reading source code in a language that's unfamiliar to
           | you shown to be of any real benefit to learning?
           | 
           | Absolutely! You start finding idiomatic patterns and "oh, so
           | that's how they do it" kind of things. Find library functions
           | you never knew about but now you do. Find weird things, and
           | look them up in a manual/reference/SO/chatroom. Things that
           | you _might_ find in a book, but a book that covers all the
           | idioms and practice and weird things is gonna be as thick as
           | the bible, and it 'll get outdated (it doesn't help that most
           | books are focused on teaching the basics rather than showing
           | off how to architect your application well). Things that you
           | can learn the hard way by why not look and see and learn?
           | 
           | > It seems you need at least a little bit of foundational
           | experience with it before your brain can even parse what
           | you're seeing in a beneficial way.
           | 
           | Nah, you just need programming experience (in a similar
           | paradigm) in general. A lot of what you learned from
           | languages before will translate.
           | 
           | Also OP mentioned that " _I can write C_ " and " _I 've
           | started reading 'Modern C'_", so it's not like they're
           | looking for their first Hello World snippet.
           | 
           | OP said they've got 15+ years of programming experience. At
           | that point, picking up a new language is all about learning
           | the vocabulary and idioms, plus the few unique or tricky or
           | quirky things that don't show up in other languages (or that
           | aren't obvious from looking at code). The fastest way to get
           | to that vocabulary is to look at real code.
        
           | pritovido wrote:
           | >Has reading source code in a language that's unfamiliar to
           | you shown to be of any real benefit to learning?
           | 
           | Yes, I think so. The parent has experience with other
           | languages, like python, javascript and go. C has a very
           | similar paradigm. If it were clojure it would be different.
           | 
           | I find exposition to new languages real usage the best way to
           | learn them. I went to the UK to learn english, Germany to
           | learn German, could be painful at first, but works, specially
           | if you know a little about what is all about.
           | 
           | Your brain makes sense of everything by itself in a magical
           | way. That is the way you learn your native language.
        
         | ctas wrote:
         | You use Lisp to write C (on Microcontrollers)? Would appreciate
         | more info on that.
        
           | cjbprime wrote:
           | Not the OP, but as I understand it NASA's JPL has been doing
           | this for decades for space missions.
        
           | williamDafoe wrote:
           | That a horrific mistake that MIT nitwhits used to teach
           | students at the end of 6.001 - how to write opaque, horrible
           | lisp programs in languages such as "C".
        
       | ryan-allen wrote:
       | I'd check out Zed Shaw's book [0]. It's opinionated, but I think
       | that's a good thing for something like C.
       | 
       | It's broken up into exercises that you start working through
       | straight away, and you start early with valgrind.
       | 
       | [0] https://learncodethehardway.org/c/
        
       | tmotwu wrote:
       | Like anything else, set yourself a goal for a project. What
       | kinds? C today is typically used for developing embedded systems,
       | kernel internals, or device drivers.
       | 
       | Depending on how deep you want to go. The most in depth way to
       | understand C is to learn assembly on an ISA first.
        
       | jennyyang wrote:
       | Get code reviews from someone that actually knows C. Mentorship
       | and harsh code reviews are the best way to learn.
        
       | vbtemp wrote:
       | First step is making sure you're using the flags
       | 
       | `-Wall -Werror -pedantic` and then one of `-std=c89` or
       | `-std=c99`
       | 
       | (Or equivalent in whatever Windows C compiler)
        
         | giomasce wrote:
         | Why would you suggest older versions?
        
       | stephc_int13 wrote:
       | In my opinion, one of the main reasons C looks old and not
       | practical to beginners is the standard libs API.
       | 
       | But it is perfectly possible to use C as a language with a more
       | modern and easier to read API, but you'll probably have to build
       | your own.
        
       | jakobdabo wrote:
       | In addition to the other recommendations, make sure you fully
       | understand the memory model of your target architecture, the
       | stack, the heap, the linkage.
       | 
       | Also, understand the undefined behavior, the compiler
       | optimizations and how it can affect your code if you forget about
       | the UB or if you ignore the compiler warnings, and read about the
       | `volatile` keyword.
       | 
       | And a personal tip, please tell the compiler not to use strict
       | aliasing (I think it's stupid) - you will get rid of some UB
       | without much sacrifice.
        
         | krychu wrote:
         | Just to be clear, heap and stack are not part of C.
        
           | Canada wrote:
           | Then why does it make a difference whether you dereference a
           | pointer to the stack or the heap at any point in your
           | program?
           | 
           | The hardware representation of an int isn't part of C either
           | but it most certainly had an effect on how your program will
           | run.
        
             | clarry wrote:
             | > Then why does it make a difference whether you
             | dereference a pointer to the stack or the heap at any point
             | in your program?
             | 
             | Ok, I'll bite. What difference does it make?
        
               | smcameron wrote:
               | Because stack pointers are short lived, while heap
               | pointers can be longer lived.
               | 
               | Say you have a queue of pointers that some thread is
               | chewing on, you can't stick a pointer to a stack variable
               | into that queue and then exit the scope of that stack
               | variable, but you could put a longer lived heap pointer
               | into that queue and exit the scope of the pointer,
               | essentially passing ownership of the pointer to
               | whatever's chewing on the other end of the queue.
        
             | krychu wrote:
             | Integer type representation is part of C.
             | 
             | See SS6.2.6.2 in http://www.open-
             | std.org/jtc1/sc22/wg14/www/docs/n1256.pdf
             | 
             | Unsigned integers are binary, while signed integers are
             | allowed one of three well-defined representations.
        
       | dandigangi wrote:
       | I learned a few basic levels of C using my subscription to
       | pluralsight.com.
       | 
       | But... I quickly switched to Rust as I see it being the C of the
       | future as it continues to develop. That's just me though. (I have
       | similar opinions towards things like Kotlin or Go.)
       | 
       | The books I am reading in the comments below are great resources.
        
       | [deleted]
        
       | haolez wrote:
       | I would focus on sources that use C11 or C18, since there are
       | some niceties in the newer standards.
       | 
       | As a reference, I like QEMU's source code[1]. It's huge, but the
       | style and practices found in any file will help you get a grip on
       | good C.
       | 
       | [1] https://github.com/qemu/qemu
        
       | vineel567 wrote:
       | I am in the same boat as you are...bare with me by no means I am
       | an expert.
       | 
       | In fact, I read couple of chapters in Modern C yesterday :). Here
       | are some of the things I am doing to improve my C skills to match
       | with some of the admired/professional developers.
       | 
       | Decide which platform to use
       | 
       | ~~~~~~~~~~~~~~~~~~
       | 
       | Unfortunately, to become proficient in it we need to write code
       | and focus on a platform. I have been fighting between whether to
       | develop on Windows vs Linux. I am very experienced in Windows
       | environment(using debuggers/cl/linkers/Windbg etc) but when it
       | comes to writing good quality C code(not C++) and for learning
       | how to write good maintainable moderately large source code, my
       | research showed that Windows compilers/C standard APIs are not
       | great, in fact they hinder your productivity. I have wasted
       | countless number of hours to just figure out how to properly
       | create a simple C project with a decent build system.
       | Unfortunately, I could not find one. The closest I could find is
       | CMake as MSBuild is a nightmare to work with. I even tried NMAKE
       | but failed. When it comes to documentation of finding basic C Api
       | usage, MSDN(https://docs.microsoft.com/en-us/cpp/c-runtime-
       | library/run-t...) does a decent job. But in the name of security
       | you will find zillion variations( __s,_ _l) of an API and by
       | default msvc compiler will not let you use some of the API in
       | their simple forms. Instead, you have to define
       | _CRT_SECURE_NO_WARNINGS etc. I think for someone just getting
       | started to develop/learn to write a decent code base in C these
       | restrictions really hinder the productivity. So finally, I have
       | decided to instead focus my learning on Linux platform(currently
       | through WSL - Windows subsystem for Linux) with its POSIX apis.
       | You know what, `man 3 printf` or `man 3 strlen` is soooooo much
       | better than googling msdn
       | 
       | Mastering C
       | 
       | ~~~~~~~
       | 
       | I think, the simple and straight answer here is reading good code
       | and writing "good" code and also reading good C content(be it
       | books or articles). I think these are the three ingredients
       | necessary to get started. Of all the open source projects that I
       | have investigated, I found Linux Kernel and related projects
       | seems to have very good taste in terms of code quality.
       | Currently, I am just focused how they use the language rather
       | than what they actually do in the project. Things like, how they
       | structure the project, how they name things, how they use types,
       | how they create structures, how they pass structures to function,
       | how they use light weight object based constructs, how they
       | handle errors in function(for example forward only goto exits),
       | how they use signed/unsigned variables etc(more of my learnings
       | to the end), how they use their own data structures. I think its
       | good to initially focus/target on ANSI C API with C99 instead of
       | heavily relying on the OS specific API on which ever platform you
       | choose. For example, such projects could be writing binary file
       | parsers for example projects like .ISO file format etc.
       | 
       | Good C projects/articles
       | 
       | ~~~~~~~~~~~~~~~
       | 
       | 1. Winlib.net - https://github.com/jcpowermac/wimlib is a great
       | source of information
       | 
       | 2. e2fsprogs -
       | https://git.kernel.org/pub/scm/fs/ext2/e2fsprogs.git/
       | 
       | 3. MUSL - https://git.musl-libc.org/cgit/musl/tree/
       | 
       | 4. General C Coding Style -
       | https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/lin...
       | 
       | 4. https://nullprogram.com/tags/c/ - great source of C knowledge
       | 
       | 5. CCAN - https://github.com/rustyrussell/ccan/tree/master/ccan -
       | great source of C tidbits from none other than Rusty Russell - I
       | haven't read all of them
       | 
       | 6. POSIX 2018 standard -
       | https://pubs.opengroup.org/onlinepubs/9699919799.2018edition...
       | 
       | continued in the comment....
        
         | vineel567 wrote:
         | My Learnings(know your language/know your complier/know your
         | tools)
         | 
         | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
         | 
         | 1. _t suffix is the notion used to denote a typedef for a given
         | type /* This example is from do_journal.c in e2fsprogs _/
         | struct journal_transaction_s { ... blk64_t start, end; ... };
         | typedef struct journal_transaction_s journal_transaction_t;
         | 
         | 2. Know about headers like stddef.h and stdint.h and when they
         | are supposed to be used. for example: When to use normal data
         | types like int vs int16_t etc.
         | 
         | 3. From https://en.cppreference.com/w/c/types/integer we can
         | sense that int_t_ are of exact width types which might have
         | some perf side effects if the underlying hardware does not
         | support the width natively.                   For example, in
         | visual studio x86/x64 we have typedef short int16_t; and
         | typedef int int32_t; int_fast_t* on the other hand make sure a
         | suitable         width which maps natively to the available
         | hardware type For example, in         visual studio x86/x64
         | typedef int int_fast16_t; instead of typedef short
         | int_fast16_t; size_t on the other hand alias to the natural
         | unsigned word         length of the hardware for example on x86
         | typedef unsigned int size_t; and         on x64 typedef
         | unsigned __int64 size_t;
         | 
         | 4. Know your compiler predefined standard macros On Microsoft
         | compiler _WIN64 - defined when we are compiling for x64 code
         | _WIN32 - defined when both x86 and x64 code is getting compiled
         | _MSC_VER - defines which compiler version are we using,
         | indicate different visual studio versions __cplusplus - defined
         | when the translation unit is compiled as C++
         | 
         | 5. We can get a FILE* from HANDLE using below APIs from io.h
         | and fcntl.h Fd = _open_osfhandle((intptr_t)Handle, _O_TEXT);
         | File = _wfdopen(Fd, L"r"); Once we get the FILE* we can use
         | fgets for line oriented string operations
         | 
         | 6. Learned about var args and aligned memory Aligned memory
         | means the address returned by the _aligned_malloc is always
         | divisible by the alignment we specify. For example: char _p =
         | _aligned_malloc(10, 4); the address return in p will be always
         | be divisible by 4. We should also free the allocated memory
         | using _aligned_free(p)
         | 
         | 7. atoi(str) this api also processes input string until it can
         | convert. For example atoi("123asda") will still give 123 as the
         | return result. Any whitespace in the beginning of the input
         | string will be ignored. So atoi(" 123asd") will still return
         | 123. It is recommended to use strto_ functions to convert
         | strings to int/long/float types as they also can return pointer
         | to the character which is a non integer
         | 
         | 8. UCRT support around 40 POSIX system level APIs but most of
         | these have _ prefix to them. wimlib in wimlib_tchar.h defines
         | #define topen _open for Win32 and #define topen open for POSIX
         | systems The take away here is the UCRT implementation even
         | though differ in name the parameters are exactly the same.
         | For example:           UCRT Win32: int _open(const char
         | *filename, int oflag, int pmode);           POSIX:      int
         | open(const char *pathname, int flags, mode_t mode);
         | 
         | 9. We can install only build tools(VC compiler) excluding IDE
         | from https://aka.ms/buildtools
         | 
         | 10. Best video on C Standard and some of its less known
         | features - "New" Features in C - Dan Saks Year C Standard
         | Comments 1983 C standard committee is formed 1989 C89 C89 US
         | standard 1990 C90 C89 International Standard 1999 C99 C99
         | Standard 2011 C11 C11 Standard 2018 C18 C18 Bugfix release
         | _reserved - Reserved for global scope. But we can use any
         | identifier with an         _ as a local variable or a structure
         | member              __reserved - Always reserved. Meaning the
         | user program should not use any         variable with two
         | underscores __              _Reserved - Always reserved.
         | Meaning the user program should not use any         variable
         | with an underscore and capital letter.              This is the
         | reason why _Bool is named that way to prevent breaking existing
         | bool typedef used in existing code.
         | 
         | 11. Another good video on lesser known C features - Choosing
         | the Right Integer Types in C and C++ - Dan Saks - code::dive
         | 2018                   we can use CHAR_BIT from limits.h
         | instead of 8 for example when you want to         print the
         | bits in a integer, we can do below `for (size_t i = sizeof(int)
         | *         CHAR_BIT; i >= 0; i--) {...}`
         | 
         | 12. size_t denotes the native architecture supported natural
         | word size. So for 32bit it is 4 bytes unsigned quantity and for
         | 64bit it is 8 bytes unsigned quantity. Hence it is defined as
         | follows                   #ifdef _WIN64             typedef
         | unsigned __int64 size_t;   //8 bytes on x64         #else
         | typedef unsigned int     size_t;   //4 bytes on x86
         | #endif              where as uintmax_t denotes the maximum
         | integer type that is available in the         language. So on a
         | 32bit you could still represent a 64 bit quantity using
         | long long even though it not what the architecture directly
         | maps to. So         below is how it is defined in both x86 and
         | x64              typedef unsigned long long uintmax_t;  //in
         | MSVC both x86 and x64 support 64         bit quantities using
         | long long. So size_t does not give us the maximum
         | unsigned integer, instead it gives us the native unsigned
         | integer i.e., on         x86 it will be 32bits and on x64 it is
         | 64bits. So recommendation is to use         size_t where ever
         | possible instead of using int. for example.              int
         | len = strlen(str); // not recommended because on both x86 and
         | x64 of MSVC int is 4 bytes due to LLP64         size_t len =
         | strlen(str); // recommended because size_t will automatically
         | maps to 4 bytes in x86 and 8 bytes in x64
         | 
         | 13. C11 introduced the concept of static asserts. These are
         | basically conditional asserts which can be evaluated during
         | compile time. So C11 has a new keyword called
         | _Static_assert(expr, message) The reason for this ugly name is
         | the same idea of not to break existing code. so for convenience
         | assert.h header provides static_assert macro which mean the
         | same. One of the use of static asserts is below
         | struct book {           int pages;           char author[10];
         | float price;         };
         | static_assert(sizeof(struct book) == sizeof(int) + 10 *
         | sizeof(char) + sizeof(float),                       "structure
         | contains padding holes!");
         | 
         | 14. Another good video on some low level details - Storage
         | Duration and Linkage in C and C++ - Dan Saks
         | 
         | 15. #define _CRT_SECURE_NO_WARNINGS can be used to disable CRT
         | warning for common functions.
         | 
         | 16. Any ucrt function which begins with _ is a non standard api
         | provided by ucrt. For example in string.h's _strdup, _strlwr,
         | _strrev are some. The take away here is, it is easy to identify
         | which function is part of C standard and which are not.
         | Interestingly some(not all) of these non standard functions are
         | part of posix so in glibc(which implements posix) don't have _
         | in them.
         | 
         | 17. All posix function in posix standard with [CX] annotation
         | indicate Extension to the ISO C standard for example, below
         | function from stdlib.h is posix extension. UCRT defines a
         | similar api called _putenv, since this is not part of C
         | standard, UCRT version has an _                   stdlib.h -
         | posix         [CX] int setenv(const char *, const char *, int);
         | stdlib.h - ucrt         int _putenv( const char *envstring );
         | stdio.h - posix         [CX] int fileno(FILE *);
         | stdio.h - ucrt         int _fileno( FILE *stream );
         | 
         | 18. Learned about CGold: The Hitchhiker's Guide to the CMake.
         | An awesome tutorial about CMake. Now it is super easy to start
         | a C project without worrying about the individual build
         | systems.                   # CMakeLists.txt - minimum content
         | cmake_minimum_required(VERSION 3.4)
         | project(command_line_parser)
         | add_executable(command_line_parser main.c)              #
         | commands to run to generate the respective native build files
         | like vcxproj files         # In below command -S standards for
         | source directory path.         # -B stands for final directory
         | where vcxproj files are generated         # CMake only generate
         | one flavor (x64/x86) per project file, here we are generating
         | x64 by specifying x64         cmake -S . -B builds -G "Visual
         | Studio 16 2019" -A x64         # we can also use cmake-gui to
         | do the above              # Once vcxproj files are generated we
         | can either directly build the proj files using Visual Studio
         | # or better use cmake itself to build it for us from CMD using
         | msbuild         cmake --build builds
         | 
         | Hope these help.
        
       | jfkebwjsbx wrote:
       | You can compile with clang on Windows, so you can use later
       | standards.
        
       | lmilcin wrote:
       | Given the fact you already know some higher level languages I
       | think the best way to learn C is to go low level.
       | 
       | C is fantastic language because it is within your reach to go and
       | understand all small details of how various features are actually
       | implemented. I find it very helpful to be able to understand how
       | a piece of code actually functions on a low level.
       | 
       | Another tip: you are used to having high level features on your
       | disposal. Don't try to duplicate those features. Figure out how
       | actual C projects deal with program structure and flow issues
       | that you are used to solving with high level constructs.
        
       | chucksmash wrote:
       | I liked "C Programming: A Modern Approach"[1]. It has been
       | several years but as I recall it was well suited for self study
       | and was pretty explicit in calling out places it was talking
       | about C99 as opposed to C89.
       | 
       | [1]: https://www.amazon.com/C-Programming-Modern-
       | Approach-2nd/dp/...
        
         | chucksmash wrote:
         | You might also take a look at this Minecraft clone in C[1].
         | Uses sqlite to persist state so you can see how you might
         | interact with a database as well. Quite modern and readable in
         | that most functions outside main.c are <20 lines long. It's
         | also cross platform and should work on Windows, Mac and Linux.
         | 
         | [1]: https://github.com/fogleman/Craft
        
       | krychu wrote:
       | The proper way to learn C is to get a good book, read it, and do
       | exercises along the way.
       | 
       | Here's an excellent book: C Programming: A Modern Approach, by
       | King.
       | 
       | Avoid online tutorials, and know that there are many poor books
       | on C, including the recommended here "Learn C the Hard Way". It
       | has factual problems; see under "Stuff that should be avoided"
       | here: http://iso-9899.info/wiki/Main_Page
       | 
       | Note also, that unlike some other languages, C is not a language
       | that you should learn by "trying things out", due to the nature
       | of "undefined behavior".
       | 
       | Another recommendation would be to ask for CR on IRC.
       | 
       | Good luck!
        
         | ianai wrote:
         | I'm always skeptical of telling people to not just try
         | something out in programming. Yes, don't just try to code up
         | the next unix without knowing any c. But definitely getting
         | your hands dirty isn't going to instill any super bad
         | mental/coding practices.
        
           | geofft wrote:
           | C is a particularly weird language: it's entirely possible
           | for things to work but
           | 
           | - secretly introduce security vulnerabilities
           | 
           | - stop working on a different compiler or after a compiler
           | upgrade
           | 
           | A generation of C programmers learned by trying things out,
           | and they left us with superstitious beliefs about volatile
           | (and also with imprisoned Uyghurs in China). We have the
           | evidence and learning C by trial and error doesn't work. If
           | you're going to write C (and there are definitely places
           | where it's the right thing to use), learn it with more
           | caution than you'd learn other languages.
        
         | giomasce wrote:
         | Since UB can be a bad beast to tackle while learning C and C++,
         | I would suggest to frequently compare what you learn with
         | cppreference.com, and check that you understand that what you
         | think matches what the standard dictates. Cppreference is not
         | the standard, of course, but is sufficiently similar and much
         | easier to read.
         | 
         | If at some point you want to really become a master, then
         | switch to the actual standard.
        
         | JustSomeNobody wrote:
         | > Note also, that unlike some other languages, C is not a
         | language that you should learn by "trying things out", due to
         | the nature of "undefined behavior".
         | 
         | I disagree. You have to learn the ways in which things fail in
         | any language you learn, especially a language like C.
        
           | clarry wrote:
           | The point is that you don't learn all the ways in which
           | things fail in C by trying. At best, you learn the way in
           | which they fail (or fail to fail!) on your specific
           | platform/compiler/version/compiler options combo.
           | 
           | If you want to know how things can fail (or, what things can
           | fail in unspecified ways), you have to do a bit of reading
           | and no amount of trying and experimenting will conjure that
           | knowledge.
        
             | zzzcpan wrote:
             | There isn't a guide to learn how things fail on platform,
             | compiler, version, options combo. Probably the only things
             | that force you to systematically research and accumulate
             | such knowledge is by writing a language VM in C or use C as
             | an intermediate representation. Even writing a C compiler
             | itself won't teach you that.
        
               | clarry wrote:
               | > There isn't a guide to learn how things fail on
               | platform, compiler, version, options combo.
               | 
               | Yeah, that's the point. Chasing that knowledge is
               | pointless. Instead, read the spec and find out what is
               | legal and what is not. What is defined and what is not.
               | Then you can stop worrying about how things fail and
               | start worrying about not doing those things.
        
               | ianai wrote:
               | Trying c out with a known solid testing framework seems
               | like a much more practical and useful way to start.
               | Telling people to read a text wall before doing any
               | practice at any task is a great setup for failure. Math
               | doesn't do that. Physics doesn't do that. Chemistry
               | doesn't do that. Literature doesn't do that. Philosophy
               | doesn't do that. Etc. and of those philosophy is almost
               | the study of text walls. But the best philosophy courses
               | tend to start with a Socratic dialogue which is basically
               | live action philosophizing.
        
       | PureParadigm wrote:
       | C is great for learning about how computers work at a low level.
       | In my college, we started by writing a simple compiler. This
       | should force you to understand pointers and memory which, as
       | others have mentioned, are fundamental. You'll have to both know
       | how the assembly works and to write correct C code. So writing a
       | simple compiler will force you to understand it two different
       | ways at once. My opinion is you'll learn more by diving in and
       | doing things, especially with your existing programming
       | background.
       | 
       | But, for your own sanity and everyone else's, do not start new
       | projects in C! (Aside from purely academic ones for you to
       | learn.) The point of a programming language is to help humans
       | write safe and correct code. In this sense, C has completely
       | failed. The syntax itself is just begging you to make a subtle
       | mistake. And due to lack of memory safety, even the most well
       | tested and scrutinized projects in C/C++ (such as Chromium)
       | suffer from buffer overflows or memory leaks, potential security
       | vulnerabilities that are automatically prevented by design in
       | other languages. If you need to do something low level with any
       | sort of confidence, use a memory-safe language like Rust, which
       | can even do interop with existing C libraries and code.
       | 
       | (Edit: typo)
        
         | bronipstid wrote:
         | It depends on what you're doing. Low level stuff pretty much
         | has to be C. But for applications I agree there are much better
         | alternatives these days.
        
           | PureParadigm wrote:
           | Yeah, there may be some situations where C is necessary as a
           | wrapper for assembly if you're _extremely_ memory constrained
           | or something like that. But I wouldn't have any confidence in
           | it working as intended unless it's dead simple.
        
       | gjkood wrote:
       | To start with, "The C Programming Langauge", Kernighan & Richie
       | (K & R) [1]. Find the latest edition that you can buy.
       | 
       | I think the primary topic to master in C is pointers. This is
       | where most falter. It takes a few years to "master" (if we ever
       | do). Here I would recommend "Understanding and Using C Pointers",
       | Richard Reese. [2]
       | 
       | If you are interested in networking, any of the classic "TCP/IP
       | Illustrated Vols I/II/III", W. Richard Stevens, [3] contain a ton
       | of C code to implement components of TCP/IP.
       | 
       | If you are interested in Graphics, then "Graphics Gems", Andrew
       | Glassner [4] is a good source.
       | 
       | "An Introduction to GCC", Brian Gough, [5] to understand the
       | tooling and its various bells and whistles.
       | 
       | My learning swimming by jumping into the deep end of the pool
       | experience was realized by learning Windows Programming using the
       | Charles Petzold book and navigating through Microsoft Foundation
       | Classes in the late 80s/early 90s. The state of the art in
       | tooling wasn't that great in those days and I spent months with
       | the book to get things going. This was done after I had built a
       | foundation with K&R and a decent amount of Unix network
       | programming.
       | 
       | I see a lot of the other posts recommend more modern books. But
       | you still need to build your foundation on C and Pointers in
       | particular.
       | 
       | Good luck on your journey.
       | 
       | [1] https://www.amazon.com/Programming-Language-2nd-Brian-
       | Kernig...
       | 
       | [2] https://www.amazon.com/Understanding-Using-Pointers-
       | Techniqu...
       | 
       | [3] https://www.amazon.com/TCP-Illustrated-Protocols-Addison-
       | Wes...
       | 
       | [4] https://www.amazon.com/Graphics-Gems-Andrew-S-
       | Glassner/dp/01...
       | 
       | [5] https://www.amazon.com/Introduction-GCC-GNU-
       | Compilers/dp/095...
        
       | Paperweight wrote:
       | Perhaps better than a book, can anyone authoritatively point to a
       | few small-and-readable but best-in-class open-source C projects
       | to use as a reference?
        
         | mlvljr wrote:
         | Sqlite
        
         | diego_moita wrote:
         | Lua and Sqlite sources are excellent.
        
           | elliotec wrote:
           | Linux as well. The comment culture of C devs really help with
           | understanding all of it.
        
             | mlvljr wrote:
             | There was a book featured in a HN post about a year ago -
             | an older Linux source with extra commentary, used by
             | students in China, I think (book is in English)
        
         | kick wrote:
         | * tweetnacl.cr.yp.to
         | 
         | Crypto library in the size of a hundred tweets [
         | https://twitter.com/tweetnacl ] by the only person with a
         | genuine claim to being able to write safe C & company.
         | 
         | * https://github.com/mit-pdos/xv6-public
         | 
         | &
         | 
         | * https://github.com/mit-pdos/xv6-riscv
         | 
         | UNIX v6 clone in ANSI C by influential Plan 9-era Bell
         | Laboratories employee and now influential Google employee Russ
         | Cox, along with influential computer virus author and son of
         | one of the original UNIX authors Robert T. Morrison; entire
         | source code fits in under a hundred pages of well-typeset
         | documents [ warning, old copy, you should generate a modern
         | one: https://pdos.csail.mit.edu/6.828/2011/xv6/xv6-rev6.pdf ].
        
         | DyslexicAtheist wrote:
         | not recent projects but everything that DJB implemented is
         | absolutely elegant, low on bugs and great as a lesson for how
         | to write secure C. e.g. qmail, djbdns, daemontools, there is a
         | lot of ideas there you can learn from: https://cr.yp.to/
         | 
         | It also helps to build up (and refactor) your toolset over
         | time, memory handling wrappers, logging, I/O, daemonize
         | (https://github.com/jirihnidek/daemon) etc, so that you don't
         | have to keep reinventing the wheel.
         | 
         | if I'd recommend one book then it's:
         | https://en.wikipedia.org/wiki/Advanced_Programming_in_the_Un...
        
         | vyskocilm wrote:
         | Any C based project of zeromq project like
         | https://github.com/zeromq/czmq is worth to read. Pieter
         | Hintjens started a book explaining all the design decisions
         | there https://hintjens.gitbooks.io/scalable-c/ Sadly he didn't
         | have a time to finish the book.
        
         | 2OEH8eoCRo0 wrote:
         | Oldie but goodie:
         | 
         | https://github.com/id-Software/DOOM
        
       | thefourthchime wrote:
       | I would read K&R, it's a right of passage. Look at some of the
       | larger open source projects for how to organize and manage a
       | large c project.
       | 
       | And practice pointers. Get really comfortable with how memory
       | works.
        
       | sramsay wrote:
       | It sounds like you're not asking, "How do I learn the language?"
       | but "How do I know I'm doing it right?"
       | 
       | I think Gustedt's book is superb if you're just trying to learn
       | the language, and it does a good job of presenting the most up-
       | to-date standard. I admire the K&R as much as anyone else, but
       | it's not exactly an up-to-date language resource at this point,
       | and it doesn't really provide any guidance on the design and
       | structure of systems in C (that's not it's purpose).
       | 
       | You might have a look at Hanson's _C Interfaces and
       | Implementations: Techniques for Creating Reusable Software_. That
       | 's focused on large projects and APIs, but it will give you a
       | good sense of the "cognitive style" of C.
       | 
       |  _21st Century C_ is very opinionated, and it spends a great deal
       | of time talking about tooling, but overall, it 's a pretty good
       | orientation to the C ecosystem and more modern idioms and
       | libraries.
       | 
       | I might also put in a plug for Reese's _Understanding and Using C
       | Pointers_. That sounds a bit narrow, but it 's really a book
       | about how you handle -- and think about -- memory in C, and it
       | can be very eye-opening (even for people with a lot of experience
       | with the language).
       | 
       | C forces you to think about things that you seldom have to
       | consider with Javascript, Python, or Go. And yes: it's an
       | "unsafe" language that can set your hair on fire. But there are
       | advantages to it as well. It's screaming-fast, the library
       | ecosystem is absolutely gigantic, there are decades of others'
       | wisdom and experience upon which to draw, it shows no signs of
       | going away any time soon, and you'll have very little trouble
       | keeping up with changes in the language.
       | 
       | It's also a language that you can actually hold in your head at
       | one time, because there's very little sugar going on. It's
       | certainly possible to write extremely obfuscated code, but in
       | practice, I find that I'm only rarely baffled reading someone
       | else's C code. If I am, it's usually because I don't understand
       | the problem domain, not the language.
        
         | johnisgood wrote:
         | I also recommend https://wiki.sei.cmu.edu/confluence/display/c/
         | SEI+CERT+C+Cod....
        
       | jerrysievert wrote:
       | while not a definitive guide, https://matt.sh/howto-c is a good
       | example of how to approach "modern" c.
       | 
       | c99 is fully implemented in windows with msvc (2015), gcc, clang,
       | and intel's compiler, so "right way" should not need to involve
       | c89. most are c11 compliant as well.
        
       | fergie wrote:
       | Pretty obvious answer, but for those who are new to C, the C
       | Programming Language by Brian Kernighan and Dennis Ritchie is a
       | good place to start
        
       ___________________________________________________________________
       (page generated 2020-03-08 23:00 UTC)