I might have to make a What has changed in C since 1980 page for old programmers. I've tried to stay current, but I learned something from this book already:
size_t strlen(char const string[static 1]);
int main(int argc, char* argv[argc+1]);
This allegedly helps prevent null pointers from being passed in, and presumably tells the analyzers and optimizers some things they should know.
It's worth a look at C11 as well, some of what you might have used gcc or clang attributes for has climbed into the language, such as _Noreturn, _Alignas, _Alignof and their friend aligned_alloc().
Addendum: Well, you can pass in pointers that go to fewer elements, but you can't pass in an actual naked null.
I didn't know about use of static keyword in array parameter declaration, but I dare to say that a lot of senior C programmers are unaware of this C99 feature.
It's nice to be able to specify function's expectations on that level, yet it looks that only clang (tested with 3.5.0) takes use of it, while gcc (tested with 4.9.1) seems oblivious to it. Be it NULL or shorter string literal than expected, gcc with -Wall -Wextra -pedantic -std=c99 spits nothing. Both mistakes are detected by clang.
Sadly even clang doesn't warn us when fun(int len, char str[static len+1]) is called like fun(5, "test").
But I'm not sure that I agree with the rule 2.11.7.1 Don't use NULL. In any sane C environment NULL is defined as follows (unless __cplusplus is already defined, because then it's defined as 0 or 0L)
#define NULL ((void*)0)
and IMHO there is nothing wrong with that.
Distinguishing kind of 0 we're dealing with (even if it's not strongly guarded by compiler) is often important for readability and eases maintenance of the code (0 vs '\0' vs NULL). While comparing pointer with NULL (writing p == NULL or p != NULL instead of simply !p or p) may seem superfluous (yet I have nothing against programmers doing so), calling function with pointer parameters providing 0 argument instead of NULL seems less clear to me.
> if you really want to emphasize that the value is a pointer use the magic token sequence (void *)0 directly.
The topic was modern C and in modern C environment NULL is defined as
(void *)0
There is no point in writing longer form and it's still clearer and safer than 0 alone.
C++ is another story with its
void* hate
built-in. In this land you rather write
(type*)0
or
(type*)NULL
(or
static_cast<type*>(0)
for extra purists), but as you're denoting pointer type already in this notation, there is not much gain in using NULL instead of 0 (well, beside grepability).
In many cases you can be done with 0 alone in C++, that's true, and in such cases NULL at least poses some intention, but if you're not careful enough, you may end up putting NULL alone (without pointer-to-type cast) in some variadic function and things start to blow up all of a sudden (that is if your NULL integer width isn't the same as pointer width). That's why having a habit of writing
Please do. I learnt C in the late 80s from rather old materials and am not fluent in the modern style. While I can "read" C mostly OK, I feel a bit like Shakespeare trying to read Snoop Dogg lyrics at the best of times. I should just invest the time to relearn C from scratch, but a primer on the changes would at least get the fire burning again.
Please have a native English speaker edit this book before distributing it. It'd be a shame to have such substantial work dismissed due to awkward use of language.
Could you provide examples for a non-native English speaker? This is really interesting to me, I have not encountered obvious (for me) mistakes in the book yet, so it's a learning opportunity.
- Pages 156 to 164 are missing (I tried to skip straight to the "Ambition" section but couldn't find it).
- The first sentence, "It has been a long time since the programming language C is around" sounds wrong to a native English speaker. Say "The C programming language has been around for a long time" or "It has been a long time since the C programming language appeared". "Since" in English generally refers to things that happened in perfect tenses (as opposed to e.g. "depuis" in French that has an imperfect tone).
This looks awesome, I haven't had the need to become more proficient at C since having learned (the basics of ) it as my first language, but this gives me some motivation to learn more about it.
I also really like that the book can be read by people of varying levels of experience, with sections devoted to different groups.
I really like C99. I've been trying to write C like that and the only problem is that there are some users who really like their MSVC from 1998 that doesn't support half of that book.
If your result can be negative, use a signed integer. But in many cases you shouldn't: unsigned integers have well-defined behaviour, you should take advantage of that.
Also, while it's true that modern C has the stdint.h typedefs, the old types are still good. All of the standard library, and many libraries you use, use the old types, so this makes interaction with them more practical. Furthermore, it'd probably best to use sizes suited to your platform. A long will be 32-bit on a 32-bit system and 64-bit on a 64-bit system. You only need long long in some cases. You can't avoid the traditional C types for things like strings, either.
Really, stdint.h only matters if you're reading binary data or performance is ultra-important, IMO.
Signed integers have undefined overflow, but unsigned integers underflow really easily.
IMO unsigned integers shouldn't have a subtraction operator named '-'. The semantics are sufficiently different that a subtraction operation on unsigneds should stand out.
(I am not a fan of using unsigned integers for semantically non-negative numbers. They are not simply a non-negative bounded type; they are a different type of integer, with a different arithmetic not familiar to everyday maths. But this is a tough row to hoe in C. Other languages, like Java and C#, didn't inherit the same mistake.)
half of it is about tools (valgrind, make, autoconf)
and it also talks about libraries (sqlite, gsl, etc...)
of course there are some chapters about the language itself
> I was thinking about buying it, but a number of the reviews I read dampened my enthusiasm.
A bit meta:
Looking for a book in a particular subject, I picked one because of a number of the reviews I read, but actually reading the book dampened my enthusiasm.
I don't know about this particular book, but if the subject is worth it it is probably also worth your time to check it out yourself :-).
Personally, I liked the book, but what the parent comment said about its contents is true. Half is tools, then the rest is mostly libraries, and then there is some stuff on the language. But if you didn't know about those things to begin with, then its very helpful.
I hate to be that guy, but I find the formatting very off putting -- especially with respect to the internal links. Compare to https://github.com/sarabander/sicp-pdf , which I find visually pleasant.
The internal links framed by a colored box are the default rendering of the LaTeX hyperref package. I also don't like them, but they seem to be pretty common, e.g. most arXiv papers do that. You can turn it off by passing the 'hidelinks' parameter when loading the package.
In addition to those hyperref settings, the code typography could be much improved. It features multiple fonts, colors and weights. I would use a single monospace font, with only a gray/black contrast for highlighting. Easier on the eyes and would look more professional.
The book claims that integer numbers wrap around. Thats not strictly true. According to the C spec the overflow behavior is undefined, how ever on all hardware known to man it wraps around. Why does it matter? Because some compilers may assume no wrap around ever happens and use this to optimize.
It's worth a look at C11 as well, some of what you might have used gcc or clang attributes for has climbed into the language, such as _Noreturn, _Alignas, _Alignof and their friend aligned_alloc().
Addendum: Well, you can pass in pointers that go to fewer elements, but you can't pass in an actual naked null.