ke...@provalid.com (Kent Dickey) writes:
> In article <
3e090bd4-4274-467b...@googlegroups.com>,
> Thiago Adams <
thiago...@gmail.com> wrote:
>
>> I am searching for C naming conventions.
>> For instance, how to name structs, function, global variables...
>>
>> Any link? What are the "classic ones? "
>>
>> I think one sample is "Win32" API
>
> Most people know they need some convention. Most people hate any particular
> convention. Pick a convention for a project, stick to it, change conventions
> for a new project. Go ahead and let sub-projects (or libraries to the
> project) try new conventions, as long as they are roughly compatible, or are
> so different as to be obvious. Don't mix conventions within a file ever.
>
> I'll summarize my rules:
An interesting set of ideas. Comments are offered in some select
cases.
> All structs must be typedef'ed and the typedef name is an initial capital.
I try to follow the rule that all (developer-chosen) type names
start with a capital letter, and no other names do. (Preprocesor
symbols are treated separately.)
> All structs are created by STRUCT(Sample_structure) where STRUCT is:
> #define STRUCT(a) typedef struct a ## _st a; struct a ## _st
It is a little bit safer if STRUCT(a) were defined
#define STRUCT(a) \
struct a ## _st; typedef struct a ## _st a; struct a ## _st
The reasons are somewhat esoteric. But since the leading
declaration is hidden inside a macro, it seems better to use the
safer form.
> The word "struct" and "typedef" should never appear in any code, other than
> the STRUCT #define.
> This means there is no typedef char **Ptr_str; nonsense to decode.
> If you see "struct", it means this is for a library/OS call.
I have a different view regarding other typedefs. However I
think I understand your motivations, and won't argue the point.
> Structure fields follow the local variable rules.
My instinctive reaction is that the rules for struct members
should be more stringent than the rules for local variables.
That said, this rule is a good baseline.
> Local variable and function names are all lower case.
Of course (with some allowances for acronyms, which might appear
as all-capitals "words" within a larger all lower case context).
> All names use _ and not CamelCase.
Generally using underscores is better than either CamelCase or
camelCase, for ergonomic reasons. An exception is type names,
where for example TreeNode arguably reads better than Tree_node.
(The type-name exception tacitly assumes that type names are
limited to at most four or five words; more than that runs
into readability problems.)
> All #defines are all-caps. No other identifier can be all-cap.
> "#define NUM_THINGS 5" is fine. #define FUNC_THIS(a) must have
> "(a)" on the right hand side in all instances. Anything more complex
> than a single number or variable must wrap the definition with ().
Generally yes; there may be exceptions in some special cases.
> Function names include the file name (or a short form of it) as a prefix.
> So serial.c would have serial_init(), serial_out_char(), etc.
> But windows_serial.c could be wser_init(), etc, just to shorten things.
> All functions in one file must use the same prefix.
Having a prefix seems reasonable. Insisting that the prefix be
tied to the file name seems excessive.
> I have a simple hungarian notation: 64-bit variables have a 'd' in the name
> that is meaningful: "dval", "init_dtmp". "do_this" is not 64-bit.
> Pointers have "ptr" in the name somewhere, often at the end (but
> "userptr2" is fine), except char * pointers should use "str" in the
> name somewhere. Non pointers variables never have str or ptr
> in the name. For your app, try to use consistent names: Don't let
> "val" be unsigned sometimes and signed other times. Pick a convention
> and stick with it. I like val to be unsigned, and tmp to be signed.
> So last_val is unsigned, and prev_tmp is an int.
> Loop counters can be i,j,k, but all other variables should briefly
> describe what it is. "tmp" or "val" are only ok for brief usage.
IMO encoding the type of a variable in its name is just wrong.
If a function has so many names that it's difficult to remember
what types go with which names then the function is too big. For
global names or struct members, if knowing the types is any
significant burden then any uses of those names should be
encapsulated, reducing their surface area.
> Declaring variables never initializes them, except for global variables.
> Use -Wall -Werror to ensure everything is initialized. This is so
> the declarations can be ignored when reading code since they
> provide no new information.
Interesting argument. I may try adopting this rule for a while.
> When passing around an array, always use &array[0] notation to indicate
> "array" is an array and not a pointer.
I follow a different rule: 'array' by itself means the whole
array, '&array[0]' means just the one element is referenced.
> The advantage of this is you can begin reading any file and have an idea
> what functions it's calling and even what work it's doing, without
> having to constantly look at header files or variable declarations. And
> the light Hungarian notation means you don't have to read declarations,
> so I pack them tightly with many variables per line just to be done with
> them. Variables are declared in order by type: arrays, then pointers,
> then ints, and by size within each type. It's not legal to mix pointers
> and ints in declarations, so you cannot do: "int a, *ptr1, b, c[100];"
My sense is that these motivations assume a style of coding that
is different from my usual style(s). And hence, consequently,
work better in some coding/development styles than others. It
would be interesting to explore that question further at some
point.
> I use special typedefs for unsigned types: byte, word16, word32, and dword64
> of the obvious sizes. These are the only typedefs that are not structures
> and are not capitalized. I'm less likely to mix them up since byte,
> word32, and dword64 are all different lengths and multiple keystrokes
> apart: word64 and dword32 are not valid. It's hard to tell uint32_t
> from uint64_t, they tend to blend together to my eyes in large
> structures, and getting them mixed up is a very annoying bug.
IMO using type names like word32 or dword64 (or uint32_t or
uint64_t) in open code is generally a bad idea. So here again I
expect that the efficacy of these particular rules depends on
program style on a larger scale.