In the past I have probably already discussed about this link here:
http://users.bestweb.net/~ctips/
That site contains tips as precious as gold, even for non-C programmers.
You can easely see that those C tips (ctips) are written by a person that has a
very large experience in programming C, more than most other person I have read
about or met.
I have never appreciated the famous book by Kernighan&Ritchie about C (despite
I use today still, mostly as a reference for the C std lib). But I have
appreciated those ctips (that are almost a book) as soon I have seen that site.
So far about C I haven't found a book or site better than those ctips, if you
know one of such references please tell me.
Those ctips are nice because they show many creative ideas (it shows things I
have believed as nearly impossible/very hard to do with D).
I like those ctips also because it shows idioms that are at the same time:
- Low level (so they are usually very efficient, both in speed and final
program size. And speed is one of the things that give power to a programmer);
- Designed to be used to create big systems, like to create C programs 100_000
lines long or more (so those idioms are designed to manage/kill high
complexity);
- Designed to be write reliable software (so they are designed to avoid bugs.
The C language is a very bug-prone language, but those ctips show ways to avoid
or quickly hunt down most bugs).
Putting together speed (a kind of power) with anti-bug/anti-complexity makes
those idioms almost universal for computers, so probably some of the ideas they
rest on can be used in other low level languages beside C.
A problem is that even after reading those ctips two times, I am partially
unable to keep them in memory and to use them. I have even troubles in copying
them down from the site pages, because there are too many details to keep in
memory, and because they are designed with an extreme rigorousness, like by an
old Tibetan monk (on the other hand I am sure that if you want to write a 200K
lines long C program, and you want a certain probability to see it actually
run, you must use more rigor than I have ever used in my small programs). The
author of those ctips can keep such idioms in memory because he has a ton of
practice of C programming.
>From a certain point of view you can think of a medium/high level as
>D/Python/Ruby/Java as a collection of idioms of low level languages, that now
>you can use at high level (OOP can be seen as a collection of idioms in C. In
>old structured programming can be seen as an idiom. In the beginning even
>routines and functions were seen as idioms in assembly programming. There was
>even people that have discussed about the pro/cons of using routines!). That
>said, to design a good medium/high language (I consider D a medium level one)
>you must choose the right idioms, the best ones.
Those ctips are a collection of good low-level idioms. I think may be a good
starting point to design a medium-level language (with power similar to C). So
they can be useful to design part of D too. Currently D has already added some
of those idioms.
--------------------
The following is a small example of one of those idioms, that I have used in a
C program to have dynamic strings. I have seen that it's faster than
alternative solutions like having a struct with size/capacity/pointer that
points to a block of memory.
I have seen this idiom works in D too (and Mystring.sizeof == 8 still) but you
can't use this idiom in D, you must always use -release.
This code is written by me, so it's NOT representative of the kind of code you
can find in those ctips, my code is surely much worse.
This stuff is error-prone, and the author of ctips agrees with this. He never
suggests to use things like this in this way. He suggests to add lot of other
stuff here, to make this thing safer, sentinels to see if there are overflows,
reflection means, more type flexibility, etc. You can't use ctips idioms half
way, you have to use them fully, and this is NOT easy.
int max2(int a, int b) {
return a > b ? a : b;
}
typedef struct { // sizeof(Mystring) == 8
int size;
int capacity;
char data[0];
} Mystring;
Mystring* mystring_new(int capacity) {
int new_capacity = max2((int)sizeof(int), capacity);
int total_mem = sizeof(Mystring) + sizeof(char) * new_capacity;
Mystring* str = malloc(total_mem);
if (str == NULL) {
printf("Error allocating %d bytes.\n", total_mem);
exit(-1);
}
str->size = 0;
str->capacity = new_capacity;
return str;
}
Mystring* mystring_append_char(Mystring* str, char c) {
assert(str != NULL && str->capacity > 0);
if (str->capacity <= str->size) {
// not enough space
str->capacity *= 2;
int new_total_mem = sizeof(Mystring) + str->capacity * sizeof(char);
str = realloc(str, new_total_mem);
if (str == NULL) {
printf("Error allocating %d bytes.\n", new_total_mem);
exit(-1);
}
}
str->data[str->size] = c;
str->size += 1;
return str;
}
If you follow those ctips fully, you end having more reflection in such data
structures than usually D gives you. That's why I have said it may be good to
have many of those idioms as built-ins in a medium-level language.
Bye,
bearophile