In C-mode and C++mode the key bindings defined by are:
cinsertblinkmatchedcharandindent.
#, }, space, tab and newline, or whose
first two characters are not // or /*, and
whose previous line last char (before newline) is not
\. Obviously the beginning of the buffer is also
considered to be a definition beginning. Made by the function
gotobeginningofcdefinition.
{,(,[
or " it goes after the corresponding
},),] or ", else it goes to the end of the
following word. A word contains alphabetic characters,
digits and underscore. Made by the forwardcform
function.
deletepreviouscform.
Indentation is parameterized by the following global variables:
The indentation rules for an empty line, for instance when you type a return at the end of a line, are (take a deep breath):
/*' position plus the
absolute value of cindentincomment. A
comment begins with `/*' and ends with `*/',
and a C++ comment with `//' and ends at the end of
line.
{}), all depends
on the previous character (skipping space, tab,
newline and comments):
`.' or `;', indentation
is set to the previous expression indentation.
`;', indentation is set to
previous expression indentation.
The indentation rules, when you indent a non empty line (for
instance when you reindent a line with a tab) depend on
the first character(s) (jumping space, tab, newline and
comments) (cheer up !, we're almost there):
#', indentation is set to 0.
*' and the next character is
`/', so you close a comment, indentation is set
to the indentation of the `/*'
`:', indentation is set to the
indentation of the corresponding `?'.
As you can see, it is rather complicated, nevertheless some cases are not taken into account and need braces. For instance it is the case for nested if like:

are poorly indented:

but the indentation is correct with braces:

Of course the quantity of code interpreted by when you type a simple return is rather disturbing, but don't be afraid, is a good boy.