Hi,
I've a few questions concerning style when programming C on UNIX systems. I
don't want to look like an amateur.
1. Having been programming in higher level languages for the last 15 years, I'm
finding it hard to get used to DEFINES in all capitals. Is it really frowned on
not to do so? Is CamelCase acceptable?
EG. '#define MaxNumFiles 1024' not '#define MAXNUMFILES 1024'.
The all-caps convention makes it easier to distinguish preprocessor
macros from other symbols. This can matter, especially when using
function-like macros (macros that take arguments). Remember that
macro expansions are simple text substitutions; a macro like
#define square(x) (x*x)
does not compute "x*x" and return a value; it *replaces* the text
"square(x)" with "(x*x)". If x is "z++", then the replacement text is
"(z++*z++)", which invokes undefined behavior. If x is "a+b", then
the replacement text is "(a+b*a+b)". By using all-uppercase for
macros, it makes it easier to see potential red flags like "SQUARE(x+
+)" or "SQUARE(x+y)".
2. My personal variable and function naming style is camel case, with variable
names beginning with a lower case char and function names not. Is that
acceptable, if not what is?
EG:
Variables: int numFiles = 0;
Functions: int CountNumFilesInDir(char* path);
That's fine. Just be consistent.
3. Is there an accepted maximum line length? I've got a 24" monitor, if I reach
120 chars I start thinking this might not look great in someone else's editor.
Side scrolling is irritating. Just make sure you break lines up
sensibly.
4. Does anyone care where the pointer * is? I prefer keeping to next to the
type, rather than next to the variable name.
EG. I like: char* firstName; and not so much: char *firstName;
It's an accident of C lexical rules that you can write it either way.
The second form correctly reflects the language syntax (the '*'
operator is bound to the declarator, not the type specifier), and
tends to be preferred among C programmers. It also guards against
potential mistakes like
char* a, b; // b is a regular char
Declarations in C (and C++) reflect the type of an *expression*, not
an object. The type of the *expression* "*firstName" is char. The
idea is that the form of the declaration should closely match the form
of an expression that yields a value of that type. If you have an
array of pointers to int, and you wanted to access a specific int
value, the expression would be "x = *a
;" The type of the
*expression* "*a" is int, so the declaration of a is "int *a[N]".
C++ programmers prefer "char* firstName", because the type of the
*object* "firstName" is char*. Fine, but what about "char
lastName[20]"? The type of "lastName" is "20-element array of char",
but we can't write "char[20] lastName". Same thing for function
types. Same thing for pointers to arrays, pointers to functions,
etc.
5. On a slightly different note, I've been handling my error messages by using
#define string constants in a header file. I saw some code which did this and it
looked good to me. Is that standard practise, if not what is?
EG. #define ErrorDirNotFound "The directory was not found."
There are so many style guides out there, most of them say contradictory things
at one point or another. What do the pros do?
I can't speak for anyone else, but I typically create a string table
and an enum to index it:
enum ErrorCodes {ErrDirNotFound, ErrInvalidPath, ...};
char ErrorStrings[] = {"Directory not found", "Path is invalid", ...};
It scales a little better than using #defines all over the place.