Larry Osterman's WebLog

Confessions of an Old Fogey
Blog - Title

What does Larry's style look like?

What does Larry's style look like?

Rate This
  • Comments 31

Sorry this took so long - work's been really busy lately.

Clearly I'm not enough of an egotist[1]  to believe that my style is in any way the "one true style", but over the course of writing the series on style, I realized that I've never written down my current coding style, and I think it would be vaguely humorous to write down "Larry's Coding Conventions".

So here goes.  I'm using the keywords defined in RFC2119 within.

Larry's Coding Conventions

1. Files - Global file information.

All source files (.C, .CXX, .CPP, etc) MUST be plain text files, with CR/LF (0x0D0x0A) at the end of each line.  Each file MUST end with a CRLF.  C++ code SHOULD be in files with an extension of .CPP, C code SHOULD be in files with an extension of .C.  Header files SHOULD have an extension of .H.

Tab size MUST be set to 4, and tab characters MUST NOT appear in source files, this allows for a user to use any editor and still have the same experience while viewing the code.

Every source file MUST start with the following header:

/*++
 * <Copyright Notice (talk to your legal department for the format of the copyright notice)>
 *
 * Module-Name:
 *     <file name>
 *
 * Author:
 *     <author full name> (<author email address>) <date of creation>
 *
 * Abstract:
 *     <Brief abstract of the source file>
 *
 * Revision History:
 *
 *--*/


Filenames SHOULD be representative of the contents of the files.  There SHOULD be one class (or set of functionality) per file.  So the CFoo class should be located in a source file named "Foo.cpp".

Global variables SHOULD begin with a prefix of g_.  Care MUST be taken when declaring global variables, since they are likely sources of synchronization issues.

Source code lines SHOULD be no longer than 100 characters long.

2. Class definitions

All classes SHOULD start with C in the class name.  Member variables of classes MUST start with an _ character.   Member variables are PascalCased (so a member variable could be _MyMemberVariable).

Classes that are reference counted SHOULD follow the OLE conventions - an AddRef() and a Release() method should be used for reference counting.  If a class is reference counted, then the destructor for that class SHOULD be private.

3. Functions and Methods - Info pertaining to various functions.

Each routine MUST have a function header, with the following format:

/*++
 * Function Name
 *
 *     <Description of the function>
 *
 * Inputs:
 *     <Description of the parameters to the function, or "None.">
 *
 * Returns:
 *     <Description of the return value, or "None.">
 *
 * Remarks:
 *     <Relevant information about the function, may be empty>
 *
 *--*/
 

Function names SHOULD be representative of their function.  All function names MUST be in PascalCase as per the CLR coding standards.  If the project is using an auto-doc tool, it's acceptable to tag the inputs closer to their definition.

Parameters to functions are also in PascalCase (note that this is a difference from the CLR coding standard).

Local variables in functions should be camelCased.  This allows for the reader to determine the difference between local variables, parameters and class members easily.

Parameter names SHOULD NOT match the names of methods in the class.

Code SHOULD have liberal use of vertical whitespace, with descriptive block comments every five or so lines of source code.

Descriptive comments SHOULD have the format:

    :
    :
    //
    //<space><space>Descriptive Comment Line 1
    //<space><space>Descriptive Comment Line 2
    //
    :
    :

Each descriptive comment starts 4 spaces from the left margin, there is a single empty comment line before and after the descriptive comment, and two spaces between the // and the start of the comment text.

Functions SHOULD occupy no more than one screen, or about 70 lines, including comments (not including headers).  This means that each function SHOULD be at most about 40 lines of code.

4. Predefined Identifiers (Manifest Constants)

Manifest constants SHOULD be in all upper-case.  Instead of using #define, enum's or const's SHOULD be used when possible, especially if the value being defined is unique, since it allows for better representation in the debugger (yeah, I know I've said that source level debuggers are a crutch, but...).

5. Code layout

Code is laid out using BSD-style - braces appear on their own line at the same indentation level as the conditional, code is indented 4 spaces on the line after the brace.

So an if/else statement is formatted as:

    if (i < 0)
    {
        i += 1;
    }
    else
    {
        i += 1;
    }

In general, unless semantically necessary, I use <variable> += 1 instead of <variable>++ or ++<variable>.

Variable declarations SHOULD appear each on their own line.

6. Code Example

The following is an example of code in "Larry's Style".

/*++
 * ErrorPrint
 *
 *     Print a formatted error string on the debug console.
 *
 * Inputs:
 *     Format - printf style format specifier
 *
 * Returns:
 *     None.
 *
 * Remarks:
 *     The total printf string should be less than DEBUG_STRING_BUFFER_SIZE bytes.
 *
 *--*/
static void ErrorPrint(LPCSTR Format, ...)
{
    int result = 0;
    static char outputBuffer[DEBUG_STRING_BUFFER_SIZE];
    va_list marker;

    va_start(marker, Format);
    result = StringCchVPrintfA(outputBuffer, DEBUG_STRING_BUFFER_SIZE, Format, marker);
    if (result == S_OK)
    {
        OutputDebugStringA(buffer);
    }
    va_end(marker);
}

 

[1] Ok, I've got a blog, that makes me an egotist, but not enough of an egotist[2]
[2] Apologies to KC for stealing her footnoting style :)

Edit: pszFormat->Format.

 

  • What the...?!??!

    Why aren't you using XML comment format?

  • That's redundant data that's very prone to becoming stale. Also, and especially with long-lived projects, these fields are likely to grow very large if they're kept up to date. Even after 10 or 20 revisions, the header is going to be huge.

    The data is already stored in your source control system, or with respect to the module name in the name of the file itself. Why duplicate this data in an error prone, unguaranteed manner? If I need to know who did what and when to a file, I'll look it up in the source control history and be assured that I'm getting accurate data.
  • G. Man: XML comment format doesn't work for unmanaged C++ code, and that's all I write these days. For C# code, I'd probably adopt to that.

    Todd: Your point is valid, the simple reason is that it's part of the Windows coding standard from way back when, and I've adopted it.
  • Hope your vacation was relaxing/exciting (delete as appropriate), and I'm glad to have you back -- I was getting a bit worried for a moment that you'd done an Eric Lippert and disappeared...

    Now, to the topic at hand -- with the exception of the indent (I prefer 2 spaces purely for aesthetic reasons -- it probably makes code harder to read, but big expanses of white space on the left hand side unnerves me) and the braces (I open on the same line as the conditional, probably as an unconscious analogy with the "Then" in Basic; 90% of my coding is in VB) your style seems to pretty much match mine.

    Unfortunately where I work there's only a few coders all working pretty much in isolation, and a lot of them seem oblivious to the benefits of consistency of style, meaningful variable names, etc. As it's all a bit ad-hoc (and most of them are senior to me) there's nothing I can do about it, but I always get a little nervous when I have to modify something someone else has worked on as I spend most of the time trying to fathom out what "OptionButton49" actually signifies; apparently even renaming widgets when you put them on a form is too much work for some people. (And one guy uses no indents at all which beggars belief.)
  • Gaah, I hate OptionButton49. It's the first thing I do when I add a control to a windows forms (or MFC) application - rename the stupid control to something meaningful.
  • Interesting. I don't work on the Windows platform at all -- I'm purely Mac OS X, worked at Apple for a number of years on various versions of Mac OS -- but I have adopted very similar coding conventions (function parameters should be in lowercase, though, and I use the Mac style for constant names). I wonder if this code style is an effect of having to maintain code written by other people.

    For just one example, I ran across a bug in someone else's code once that looked like this:

    thing[i++] = i;

    Here, the value of i is undefined per the C standard, so Microsoft VC was doing one thing with it, and two different versions of CodeWarrior did two different other things with it.

    I had been previously warned away from the increment operators by more experienced hands, but that bug certainly put me off them for life.
  • Chris, code like that's exactly why I avoid expressions with side effects.
  • Nick, that's because you've not actually written code using true hungarian (not the hungarian you see in the MS examples).

    Once you've spent a month or two writing hungarian code, it's not NEARLY as bad as you'd think, and in many ways it can be quite nice.
  • I've enjoyed all your entries on coding style and agree with almost everything you say.

    I used leading underscores for member variables in the past until I came across the advice of Herb Sutter (Exceptional C++, Item 20) to avoid them. To quote:

    "Yes, popular books like Design Patterns do use leading underscores in variable names, but don't do it. The standard reserves some leading-underscore identifiers for the implementation, and the rules are hard enough to remember—for you and for compiler writers—that you may as well avoid leading underscores entirely[1]. Instead, my own preference is to follow the convention of designating member variable names with a trailing underscore."

    He goes on to give examples in which some implementation use #define macros that stomp all over member names.
  • Simon,
    That's a REALLY good point, there IS a conflict with reserved names. The good news is that it's unlikely that the language specific features will be PascalCase - I know I'm playing with fire though.

    On the other hand, I don't write code for cross platform applications - the only person I write code for is Microsoft (and this blog).
  • pszFormat or Format? Maybe they're not supposed to be the same variable, but it seems confusing to (partially) Hungaianize some string variable names but not others. Or would it be PszFormat to give your Pascal casing?

    Thanks for not using on lpcwszFormat. Ick!
  • I know this is off-topic but why is everyone always ragging on the pre-processor directives (Macros)? I find #define, #if, etc etc very useful in my code and have never had a problem with them.

  • > (so a member variable could be
    > _MyMemberVariable).

    I used the mouse to copy that as soon as I saw it, preparing to paste it. Then another language lawyer beat me to it, but then you continued:

    > The good news is that it's unlikely that the
    > language specific features will be PascalCase

    What do you mean by "language specific features" and what is the relationship between them and the standard? When your program has undefined behaviour, an implementation is free to do anything including defining a meaning for your program and doing what you wanted. Meanwhile, not only are other implementations free to do whatever they wish, but your favourite implementation is free to change its mind tomorrow.

    > I know I'm playing with fire though.

    That's only part of it. You're also firing random bullets at your customers. And maintainers inside your company who have to clean up your code will hate you.

    By the way, someone once taught me a clever trick, to name arguments of function-like MACROS with a single leading underscore, but of course followed by a lower-case letter not an upper-case letter. No other identifiers would start with an underscore except for those defined by the standard, and except for those defined (and documented) by an implementation when the application needed to use an implementation-defined feature. This really helped assist the readability of macros. Of course when reading the rest of the program it's still not easy to look and guess whether an innocent-looking function call is really a macro containing a goto of some kind or other, but that problem exists regardless of underscore usage.
  • Norman: Language specific features: The _ is reserved for local extensions of the C standard - those are either language specific changes (new reserved identifiers like __gc in C++/CLR) or runtime library extensions (like _strnicmp).

    Manip: The problem with Macros is twofold. First, they don't appear in the symbol file, thus they don't show up in symbolic debuggers, second that the hide complexity.

    Drew: I missed that, thanks for pointing it out.
  • Oh, and Drew: the correct hungarian for a const wchar * is wsz - hungarian doesn't differentiate between const and non const (I need to verify this when I get back to work). Either way, for 32bit flat code, lp isn't part of hungarian, and the const can't be a prefix of 'c' because the 'c' prefix is for count - lpcwsz is a long pointer to a count of wide character strings.
Page 1 of 3 (31 items) 123