Code indentation is a very personal thing; people use 2, 4, 8, or any other amount of whitespace to align their constructions. However, few of them pay attention to the usage of spaces or tabulators to accomplish what they want. Some others do, but problems remain. Let's analyze what these are:

Many text editors try to be smart and replace groups of eight spaces by a tabulator character. This may seem like a good idea to reduce on-disk space, because the resulting document will usually look the same. But IMNSHO, this is a very big mistake. The code ends up with such a mixture of spaces and tabulators that it's almost impossible to edit them easily, specially if you have to change the indentation of a block of code (either manually or automatically). Consider the following chunk of code:

void function(void) {
if (...) { // 1 tab
statement1; // 2 tabs
statement2; // 16 spaces
statement3; // 1 tab 8 spaces
} // 8 spaces
}

Ridiculous, isn't it? Of course it is, but it happens a lot. Now, suppose Joe the user sets up his editor to show tabulators as two spaces. He will see the following:

void function(void) {
if (...) {
statement1;
statement2;
statement3;
}
}

What a neat result. It gets even worse if the original writer does not use 8-spaces for tabulators. Just try to do a less over the file afterward; you'll be scared.

Some other people think that, by using tabulators, people will be able to read the code following their indentation preferences; i.e., adjusting the tabulator size (what we did in the previous example). Hahaha, what an utopia!

The first problem is that lines will be too long (or too short, but this is not a problem). Suppose you configure your editor to treat tabulators as two spaces. If you care about readability, you will write text until you hit the right margin of the screen, and break the line at that point. OK, good. But now, another reader looks at the code with a size of eight, and all lines wrap into multiple ones.

The second problem is that, to achieve what you want, you will have to pay a lot (and I really mean that) of attention to indentation, basically because your editor will keep doing nasty things. Consider this chunk of code:

void function(void) {
if (...) { // 1 tab
(void)printf("very long string", // 2 tabs
arg1, arg2); // 3 tabs, 5 spaces
} // 1 tab
}

Note that we originally wanted to align the line containing arg1 to end up just after the parenthesis of the printf call. That line has three tabulators, but its indentation level is two. Therefore, it should only have two tabulators and 13 spaces. Otherwise, Joe looks at that code again, with a setting of two spaces per tabulator, and he sees:

void function(void) {
if (...) { // 1 tab
(void)printf("very long string", // 2 tabs
arg1, arg2); // 3 tabs, 5 spaces
} // 1 tab
}

Again, an ugly result.

Conclusion: handling code with mixed tabulators is difficult; too difficult to even worry about it. I've seen many projects (Boost, for example) banning their usage, and I do understand them. Personally, I use an indentation level of four spaces and completely disable tabulators from my editor, usually Vim. If you wonder how to do it, add the following lines to your ~/.vimrc file:

set expandtab
set shiftwidth=4
set softtabstop=4

And here are some minor goodies for GNU Emacs, which can be placed in your ~/.emacs file:

; Set the default fill column to something wider.
(setq default-fill-column 75)

; Highlight trailing whitespace in lines.
(setq-default show-trailing-whitespace t)

; Do not use TABs to indent, unless a buffer overrides it explicitly.
(setq-default indent-tabs-mode nil)

Edit (Feb 27th): Some minor changes in the code examples' comments.