easy as the C
C was not my first programming language. At some point I figured that there is a lot of Open Source software written in C out there, and contributing would require to learn it.
Recently I've discovered JoeQuery's blog which has a nice learning C series (amongst other really cool stuff). It inspired me to write a post about C.
If you are new to C you'll read a lot about dangerous macros, arrays and pointers, how you should handle dynamic memory allocation etc. All theses points are very important, but here is an attempt to sum up more general concepts that you are less likely to find in most C tutorials. If anything, it's a good summary of what I would have liked to read when learning C (maybe I did but forgot — there are some things you only learn by shooting yourself in the foot).
C is *very* different from C++
C++ differ from C in a vicious way. Someday, you might cross the path of
some C++ code that will really looks like C.
Do not try to transpose what you learn in C to C++ (even though
you see struct
or enum
). You'll do better if
you think of them as two unrelated separate languages, because that's
what they really are today. I guess the opposite is also true, watch out
if you're learning C coming from C++.
There are many of them
You'll read a lot about "the C programming language". Truth is there are a
lot of different kind of C and even more C environments (platform).
Knowing your C standard (or variation) and your environment is a real
plus when searching for accurate documentation and help.
To get which standards are known to your compiler, check its manual about
the -std=
option. If you feel lost the
Wikipedia page about C
is a good start. About your environment it's your OS (and when it's
something else it will be obvious).
On a non-technical level, C has also many different communities with different cultures. Keep it in mind while contributing to other projects; it is always welcome to check the habits, guidelines and preferred style beforehand.
C has no namespaces
There is no built-in support of namespaces in C, but instead a long
tradition of prefixing. It is important to note that
prefixing with _
or __
is reserved for the
implementation of the system
(the compiler and C environment) . You'll read (maybe use) stuff
belonging in these "reserved namespaces" and that's OK, but avoid them
for your own variables, macro, and functions.
Try clang for development
clang is, like
GCC, a C compiler (though both can compile
other languages too). When clang started to
become a serious alternative to GCC,
Expressive Diagnostics
was a very attractive feature. Back then understanding
GCC diagnostics was a very painful
remember-by-heart-what-kind-of-error-that-cryptic-message-could-report
process. For example,
error: expected '=', ',', ';', 'asm' or '__attribute__' before 'foo'
was usually related to an unknown type (you could have mistyped
int
or forgot to include a header). While
GCC has since improved, I still do prefer
clang's default warning flags and diagnostics.
This is really about personal taste though, so my advice is to
play a bit with both GCC and clang to make your own mind.
UB
C is notorious for "Undefined behavior". For example, if you divide by zero most "high level language" will throw an exception or the program will abort somehow. In C you'll get an UB, meaning it's impossible to know what will happen.
UB are tricky. If you are unlucky lucky, the program will
continue to run with a potentially corrupted memory / stack, and debugging
will be like wandering through a dungeon without a light torch where it's
pitch black and you're likely to be eaten by a
grue.
As it has been correctly pointed out to me, having UB allows compiler a whole class of optimisations. The LLVM blog posts series What Every C Programmer Should Know About Undefined Behavior explains it in details with simple examples. Thanks to grim7reaper for both the info and LLVM blog's reference!
Rigorously checking pointers and returned values for errors along with using tools like gdb, Valgrind and scan-build will save you a lot of debugging time.
premature optimization is the root of all evil
Programmers waste enormous amounts of time thinking about, or worrying about, the speed of noncritical parts of their programs, and these attempts at efficiency actually have a em negative impact when debugging and maintenance are considered. We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil. Yet we should not pass up our opportunities in that critical 3%.
This is especially true with low level languages like C where you get to manage memory yourself. Keep it simple and stupid because most of the time n is small.
That's it!
Feel free to add your advices and tips about C in the comments section :)