
To become a good C programmer (2011) - __john
http://fabiensanglard.net/c/
======
simplicio
I found that, after learning the basics of the language via K&R or a similar
book, the best way to get a good understanding of C and its weird corner cases
and eccentricities is just to go through the comp.lang.c FAQ page.
[http://c-faq.com/index.html](http://c-faq.com/index.html)

It's pretty comprehensive, and I found the level was pretty good for a "not
total newbie, but still not familiar with the subtilties" level that can be
kind of hard to find resources for.

~~~
blaisio
Making a blogging engine in C would be very informative (though difficult).

~~~
aastronaut
i think fefes cms is written in C... [1]

[1] [http://www.fefe.de/poweredby.html](http://www.fefe.de/poweredby.html)

~~~
majewsky
Eeyup. A 2009 version is archived at
[https://erdgeist.org/cvsweb/Fefe/blog/blog.c](https://erdgeist.org/cvsweb/Fefe/blog/blog.c)

The best part is that where stores his posts. SQL? Nope. NoSQL? Nope. Plain
text files? Nope. Fucking LDAP. [1]

[1] Source:
[http://blog.fefe.de/?ts=a8d61c27](http://blog.fefe.de/?ts=a8d61c27)

------
joshumax
When I first started out with C (and back at that time it was the first
programmimg language I started learning) I read a majority of the "standard"
books and felt rather confident in my understanding of the basics, but when it
came to actually _writing_ C, I never felt like I was writing good, pragmatic
code. So I started combing through the sources of popular FOSS software like
gtk, musl libc, Linux, OpenRC, gcc, etc, submitting bugfixes for a few of
them, and asking for code reviews on mailing lists until I finally thought
that I was doing okay. I still felt like my knowledge was lacking though, so I
decided to learn the internals of the modern x86 machine by writing a hobby OS
resembling MINIX (I think I even got X working at one point). Despite still
not being the best programmer, it really helped with my understanding of why
things are done in C like they are.

~~~
greenpenguin
This sounds like a good way to learn, but I would worry about picking up bad
habits. Do you have any recommendations of (C) projects etc. that are
particularly well written?

------
optforfon
The more I learn C the more I hate it. At first it seems simple and easy but
reading "Expert C Programming" is reading a laundry list of what's really
messed up with the language. 80% of the problems would be solved by some sane
syntactic sugar that compiles down to C

~~~
ams6110
I would say generally I feel that way about any language I've learned.
Initially they are pretty easy and the examples given include slick solutions
to contrived problems. Then you get into wanting to do real work and you learn
about all the corner cases and ambiguities and landmines that are hidden
farther afield.

Can anyone name a language that they've grown to like _more_ the more they
learned about it? I would guess maybe only those in the LISP family would make
the cut.

~~~
ArkyBeagle
My favorite language remains 'C'. You don't have to even look at the corner
cases, landmines and ambiguities - use the subset of the language that works.

Other than things like signed integer weirdness, most complaints about 'C'
revolve around the library. Well, don't use those parts of the library.

~~~
optforfon
Except that generally the point of using C is to squeeze performance out of
your alogorithms - so you can't limit yourself. But even the simple
straightforward stuff has been done just sloppily. I think we just take for
granted that it's part of the learning curve and that programming just isn't
easy.

And eventually your fingers memorize all the nuanced and sure if you don't
screw up it all works. But it's designed in a way where you end up shooting
yourself in the foot. It's hard to reason about pointer and reference
notations, everyone eventually miss a break in a switch - const is weird,
arrays vs. pointers is weird. Symbols are needlessly overloaded to do
different hings. Things that seems like they'd work for strange reasons don't
EXAMPLE:

foo(const char __p) { }

main(int argc, char __argv) { foo(argv); }

I really really recommend opening up "Expert C Programming". I promise by page
50 you will be angry - not because there are so many gotchas, but because most
of them are completely fixable. Just no one has bothered to do it

------
autarch
I cannot recommend Understanding and Using C Pointers by Richard Reese highly
enough ([http://www.amazon.com/Understanding-Using-Pointers-
Richard-R...](http://www.amazon.com/Understanding-Using-Pointers-Richard-
Reese/dp/1449344186))

Learning C syntax is pretty easy. Learning to use the standard library is
mostly a matter of reading man pages and other people's code. But I found
understanding pointers and memory management completely opaque until I read
that book. It definitely brought me from "beginning C hacker flailing about"
to "intermediate C hacker flailing about in a more dangerous way".

------
halayli
You can be an excellent C programmer but still create horrible abstractions.
Programmers underestimate the art that goes into that.

------
scarmig
K&R is often recommended, and it's certainly fun to read and accessible. But
I've also heard it's outdated, and doesn't rally focus much on modern C
software design, mostly because the world knew little about it when K&R was
written.

Thoughts?

~~~
dsfuoi
I think the style should be avoided; code shouldn't be compact and variable
names should be descriptive.

Artificial example:

    
    
        for( int i = 0 ; i < c+j ; i += b )
    

should be:

    
    
        for( int count = 0 ; count < sum+extra ; count += skip )
    

It may be allowed to use _i_ in place of _count_ here, but this is the only
place where single name variables should be permitted and only if _i_ is
really just a simple array index iterator.

~~~
tmuir
Even "i" can be changed to "index". My rule of thumb is this: If you wouldn't
use the abbreviation when speaking, don't use it when coding.

I don't understand why 'i' has been given a pass. The argument boils down to
saved keystrokes. Typing is not the bottleneck.

~~~
dllthomas
> I don't understand why 'i' has been given a pass.

Because it is well enough established (in both programming and mathematics)
that it communicates literally no less information to the reader than
"iterator" or "index" would in the same context.

> The argument boils down to saved keystrokes.

Not at all. I, for one, find it easier to see the shape of the whole
expression when the variable names are shorter.

~~~
kps
Yes; prolixity yields clarity in programming about as much as in prose. The
old quip needs an update: a modern programmer can write COBOL in any language.

------
dsfuoi
This is the first time I have seen sizeof used like this:

    
    
      sizeof( &array[0] )
    

This looks equal to:

    
    
      sizeof( array )
    

at first glance, which would give the size of the entire array in bytes, but
of course the &array[0] expression is really:

    
    
      &*( array + 0 )
    

which simplifies to:

    
    
      array + 0 
    

which is a pointer. And using sizeof on it gives the size of a pointer to int.

Edit: (&* array) will also give a pointer.

\---

This is just a really convoluted way to write 2:

    
    
       &array[2] - &array[0]
    
       &*(array+2) - &*(array+0)
    
       (array+2) - (array+0)
    
       2 - 0
    

Again I have never seen this written in such fashion.

~~~
robertelder
Here are the relevant parts of the C standard:

C89 3.3.3.4

"The sizeof operator... When applied to an operand that has array type, the
result is the total number of bytes in the array."

C89 3.2.2.1

"Except when it is the operand of the sizeof operator or the unary & operator,
or is a character string literal used to initialize an array of character
type, or is a wide string literal used to initialize an array with element
type compatible with wchar_t, an lvalue that has type ``array of type '' is
converted to an expression that has type ``pointer to type '' that points to
the initial member of the array object and is not an lvalue."

Additionally, here is a thread of Linus Torvalds pointing out even more of the
confusing nature of arrays and sizeof in C:

[https://lkml.org/lkml/2015/9/3/428](https://lkml.org/lkml/2015/9/3/428)

~~~
ucs
_Additionally, here is a thread of Linus Torvalds pointing out even more of
the confusing nature of arrays and sizeof in C:_

I really like the idiom for passing sized arrays suggested at the end of that
LKML thread[1]: pass them by reference!

    
    
      void func(int (*arr)[256])
      {
        printf("arr size: %ld\n", sizeof(*arr));
      }
    
      int main(void)
      {
        int array[256];
        func(&array);
      }
    

[1] [https://lkml.org/lkml/2015/9/7/147](https://lkml.org/lkml/2015/9/7/147)

------
vshan
Lots of good book suggestions in the Ask HN thread I had posted earlier:
[https://news.ycombinator.com/item?id=11560509](https://news.ycombinator.com/item?id=11560509)

------
genop
"And no good book is as good as disassembly output."

[x] Strongly agree [ ] Agree [ ] Neutral [ ] Disagree [ ] Strongly disagree

For me, C, i.e., GCC, is most useful as a faster way to generate assembly for
a particular CPU than typing it out from scratch. I use GCC as a code
generator. I'd like to see more free asm code generators, but I am not holding
my breath.

I do appreciate C as a medium for distributing reasonably efficient software.

~~~
umanwizard
I don't really understand what this means. How is that different from how
anyone else uses a compiler?

~~~
omginternets
I think he means that he works like this:

1\. Write some C

2\. Dump the corresponding assembly code

3\. Modify the code by hand

~~~
genop
4\. Assemble

5\. Load into assembly debugger

6\. Learn

There is "C", the language, which can be relatively simple. Or hopelessly
opaque depending on the author.

I think of C the language as just a shorthand for assembly. Only because
that's how I use it.

[http://www.lysator.liu.se/c/bwk-tutor.html](http://www.lysator.liu.se/c/bwk-
tutor.html)

But then there is "C" in practice: the specifications, the "standard"
libraries, preprocessors, Makefiles, autoconf, etc.

~~~
umanwizard
But what would qualify as an "asm code generator" if not a compiler? There are
other free compilers. Clang comes to mind.

~~~
Annatar
Let us see... in my day, we called an "asm code generator" an assembler...
anyone remember MasterSEKA, Devpac, TRASH'M-One and ASM-one?

~~~
genop

      1. Program that reads some input (e.g., C language) and generates asm and/or opcodes.
      2. Program that reads asm and/or opcodes and generates binary numbers ("object files").
    

No. 1 is what I need. No. 2 is what I call an "assembler". Although
terminology means less to me than what a program actually does.

~~~
umanwizard
No. 1 is literally the exact definition of a "compiler". I still don't
understand the distinction you're making.

~~~
genop
That's because it is a compiler.

No. 1 is a program that accepts input (e.g., RTL, MINIMAL, etc.) and generates
asm.

I like to call this an asm code generator. Because today when people say
"compiler" they are often referring to a collection of programs, some of which
do not generate asm.

~~~
umanwizard
I see. So you are excluding the preprocessor, linker, type-checker (for some
languages this is a separate program), assembler, etc.?

~~~
genop
Yeah. I'm sorry about the terminology. I guess I just like the term "code
generator".

When I use that term I envision simple filters that take ASCII input, maybe
even some sort of "template", and transform it into some other format that's
useful. Ideally, asm. But not always.

For example, in GCC, for x86, there's a couple of programs that operate on
i386-opc.tbl and i386-reg.tbl. I would not call them "code generators" but I
suspect they are needed in order for "gcc -s" to work.

------
onetimePete
the biggest virtue of a c-programmer is temporary forgetfulness.

forget for the moment, that all of the old-guard-tech foundations is basically
a castle made of glued together jello filled rubber ducky's. forget all the
tricks needed to jump through that final hoop in assembly. forget even those
hopeful endeavors of the languagewiser that stood up, and then came back
because performance is a bitch and there use cases to edgy. forget all those
library's that overpRomised, undereallocated and disspointered. forget all the
futile attempts to steer this boat, carried on the hands of the likes of you,
towards some sail-able waters. blissful unawareness settles in, while every
"good c-programmer" near you starts to spit fire as soon as management
declares a new megalomaniac project in C worthy the effort and thus starting.
forget that strange feeling of elated Shame of being the best to repair the
most broken car in town.

Then, and only then, you will be a "good" C-Programmer, one that knows all the
tricks of trade, while not getting wiser.

------
javajosh
Very cool. I would like to see a similar recommendation for TCP/IP, DNS, and
perhaps HTTP 1/2, including SSL. (Although I suppose you could start with C
and then just get involved with the linux kernel, linux net utils, and nginx.
But that's like, hardcore.)

~~~
MichaelMoser123
i think 'TCP/IP Illustrated' is good if you want to get into networking.

------
icdxpresso
I'm interested in learning about reverse engineering and malware analysis. Is
learning C the proper first step in getting my hands dirty? I used C++ in a
few college courses, but I've been primarily a Java developer for the past two
years.

~~~
tboneatx
Definitely C, and you will also need to know a fair bit of assembly. Also
familiar yourself with the PE (portable executable) format and learn how to
use IDA disassembler and possibly SoftICE (Not sure if it still works, but it
was/is a very powerful kernel debugger)

------
jsnk
What's a good practical but small enough project you can do with C? Typically
if you are learning Ruby or Node, people recommend creating a blog. What's
something like that for C?

~~~
stevetrewick
A virtual machine and assembler. This is actually pretty straightforward and
lots of fun.

~~~
mastax
Along the same lines: an emulator for an old computer or games console.

------
agumonkey
What other experiences, non C based, will make you a better C programmer too ?
ADA, ML, Forth ? some other academic domain ?

------
kyled
Learn assembly then c will be easy

