Passion/Editor

코딩 스텐다드

sunshout 2006. 9. 10. 20:03

Coding Conventions

General

  • All software should compile and run on Unix-based and Windows XP-based systems if at all possible.
  • For larger projects (not homework assignments), use Unix autoconfig and automake, so that installation reduces to
    ./configuremakemake install
  • For larger projects (not homework assignments) on Linux, create RPM packages.

C and C++

The formatting indicated below can be accomplished by
/usr/local/gnu/bin/indent -i2 -kr file.cexpand file.c

General

  • Your code should compile warning-free under gcc -Wall.
  • Avoid code duplication unless there's a very good reason. Copy-and-paste of existing code is tempting to get new code working, but it's almost never a good idea -- bug fixes or improvements in one version of the code won't get propogated to the other one. Instead, break out common parts of the new and old code into functions you can call. If you don't feel you understand the old code well enough, ask someone who does.

File

  • Each file should contain, unless generated automatically or for special cases
      Copyright (c) year by Columbia University. All rights reserved.
    where year is the current year.
  • Files that are automatically generated should contain
    THIS FILE WAS GENERATED AUTOMATICALLY BY XXX. DO NOT EDIT!
  • Functions that are used elsewhere should be in .h files; strictly local functions ("private" functions) should be static. That way, we know which interfaces are being exported and which ones aren't.

Naming

  • If you're modifying code, follow idiomatic usages of that code. For instance, if the file you're in uses underscore_separated_names, don't add new functions that use IntercapSeparatedNames.
  • Types are defined with the name _t, as in codec_t.
  • Variable naming conventions:
    pointers prefix with p pMemberlist

Functions

  • The enclosing brace for the function is followed by the name of the function as a comment. This makes it easy to identify where a function ends.
  • Functions should not be longer than one editor screen (at most 50 lines) or four levels of nesting, except when the function is a long list of 'switch' cases. Files should not be longer than a few hundred lines. If you need to make an exception, put a comment at the top of the function explaining why.

    In C, when you break functions out of the code you're calling, declare the broken-out functions static. This stops accidental namespace pollution. In C++, if you're breaking up member functions and the broken-out routines need access to data members, declare the broken-out routines as private member functions instead.

  • Functions are separated by two blank lines. In other words, there should be two blank lines between the closing brace of a function and the opening /* of the next function. You can have one line after macro definitions, global data, etc. More blank lines are acceptable between major conceptual parts of a file.
  • Function names should start with the module name (e.g., Audio in the example above), contained in a file of the same name. That makes it easy to figure out which file a function is defined in, without having to 'grep' each time. Externally visible function names should be in CamelCase, e.g., AudioInput.
  • All externally-visible functions must appear in a .h header file, with the same name. In the example, audio.h. Other functions should be declared static. Definitions (templates) in a file itself are unacceptable, except for forward definitions of static functions.
  • For prototypes of functions defined in a C file which might be called from a C++ file, the header file should contain prototypes in the following format:
        #ifdef __cplusplus    extern "C" {    #endif       /* ... prototypes here ... */    #ifdef __cplusplus    }    #endif

Indentation and Bracketing

  • There should be no spaces immediately after opening, or before closing, parentheses. Thus, write
            if (condition1 && condition2)
    rather than
            if ( condition1 && condition2 )
    The latter calls too much attention visually to the parentheses themselves, when it's the condition that's relevant.

    One exception: it's acceptable to space-out the outermost parentheses if your parentheses are deeply nested, if it makes things visually clearer. (But if your parens are so deeply nested as to require this, you probably want to re-write your code to break up the expression anyway.)

  • Format your code for approproximately 70- to 75-character lines. Much wider than this linewraps badly with diff; much shorter than this makes code look too sparse. A line of code must not exceed 80 characters.
  • Use 2-space indent rather than tab, as tabs often don't print right and render differently on each editor. To get emacs's indentation modes to use spaces instead of tabs, add the following line to your .emacs file:
    (setq-default indent-tabs-mode nil)
    For vile, insert the following into .vilerc
    unset tabinsert
  • C control constructs:
      if (x) {  }  switch (x) {  case '1':    break;  case '2':    break;  }
    with spacing around () as shown for readability. For deeply nested control structures, it is helpful to include the nesting in a comment:
      if (x) {    while (y > 1) {      for (i = 1; i < 10; i++) {      }    } /* while */  } /* if */
  • The opening braces of if, for, while, etc., blocks -- all blocks other than the top-level function blocks -- go on the same line as the opening condition. The closing braces go on a line of their own.
  • Always enclose the bodies of if, for, and related statements in braces. Don't count on the fact that a single statement following the if (or whatever) will be enclosed in the if -- it's asking for trouble for future code maintenance.
  • Main function:
      int main (int argc, char *argv[])  {    return 0;  } /* main */

Comments

There isn't a particularly rational reason for the style below, except that it seems to work and it's what a lot of the existing code does. It's a lot easier to read code if it's all formatted the same.

  • Comment. You knew this.
  • Each file starts with a comment similar to the following:
    /* * message.c: manipulate messages and message queues. * Copyright 2001 by Columbia University; all rights reserved  */
  • We have CVS; there is no need to keep the revision history in the file. It's never up-to-date, anyway and just makes the files be bloated. Code historians can consult CVS; the rest of us doesn't care. (CVS only applies to student projects and other long-term software projects, not homework assignments.)
  • There's no need to "sign" your code (comments along the line "/* Added by John Doe for the handling of earthquakes */" are unnecessary.)
  • Don't comment out, or #ifdef-out, old code. Just delete it. If we want to know what the code used to look like, we can use CVS -- that's what it's for. If you have code that's partially written but isn't ready yet, the best thing to do is not to check it in to CVS. If this isn't possible, make sure you have *prominent* comments -- probably with an XXX comment -- saying why the code has to be commented out for now, and what needs to be done before it can be fixed.
  • Keep your comments up-to-date with your code. If you fix a bug, for instance, remove any "XXX: need to fix bug" comments.
  • Periodically, grep for XXX. If an XXX persists across a release, this is a bad sign.
  • Generally, includes should list the functions:
      #include <stdio.h>  /* printf(), gets() */
  • Try doc++ for generating program documentation. Similar programs exist for PHP.
  • Each function must be commented. If you don't do it now, it won't get done. Each file should also describe its function and last modification date (via RCS, i.e., $Id$). The file-level comments should indicate which external packages are needed. Example:
    /** AudioInput()* Receives audio from microphone input, performs silence detection (if* flag 'silence' is 1) and applies the codec 'codec'.  Returns the* number of bytes read or -1 on error. */int AudioInput(int silence, codec_t codec){  ...} /* AudioInput */
    • function_name() is the first line of the comment. It has parentheses, but no return value or argument.
    • function_name is the comment on the same line as the closing brace. This lets you know immediately what function is ending when you see a closing brace.
    • The *'s in the initial comment block are lined up with the * in the opening /*.
    • The opening brace of the function is on the next line from the function.

    For C++ code, use the above style for extern "C" functions. For non-extern "C" functions, this style is ambiguous because C++ supports function overloading. Thus, in C++, use the following style:

    /* * a_class::function_name(bar_t *bar, int baz) * Do foo to bar.  If baz is true, also do quux. * Return false on failure. * XXX: also need to bletch. */int a_class::function_name(bar_t *bar, int baz){} /* a_class::function_name(bar_t *bar, int baz) */
  • Top-level things that aren't functions (macro definitions, global/static data, etc.) don't need the names, but should have a /* */ comment block.
  • "House style" for comments:
      /* Single line comments (space between * and word). */  /*   * Multi-line comments, such as these.   * And more. Note that the first and last line are empty.   */
  • All variables must be commented.
  • Use sentence fragment above each significant or non-intuitive block of code.

Other Conventions

  • Types may use the _t convention, as in
      struct queue {    struct queue *next;    int data;  } queue_t;
  • In C++, there should be no public data members. All data members are accessed through public methods. In C, access to complex structures should be through specific accessor functions. This is needed, for example, to enable late parsing of messages.
  • Never use non-boolean values implicitly as booleans in an if, while, or for statement. Instead, explicitly compare with or against the appropriate zero value for the type. For example, use
      if (p != NULL)  if (strcmp(foo, bar) == 0)
    rather than
      if (p)  if (!strcmp(foo, bar))

    There's no inefficiency with the former statements -- the compiler knows what it's doing -- and it's a lot clearer, when reading code, what you mean, and what the type of your variable is. (This one may be controversial. The 'if (p)' and '!strcmp' idioms are awfully common, but they obfuscate code without adding anything useful.)

    Note, though, that if a function does return a boolean value, using it directly in a boolean expression is entirely appropriate, and explicitly testing it != 0 (or worse, explicitly testing it == 1) is a bad idea.

  • Error messages are written to stderr, not stdout. There should be a common error logging function, so that we can easily redirect this as needed.
  • When you're printing debug or error information, include information about the context of the bug. For instance, if you're handling a request structure r, debug messages should typically look like debug("Function", "Request 0x%p: Something's wrong\n", r); (though of course you'd use a more descriptive debug message!)
  • Debug messages should not just be printf, with comments when not needed. Use a debug command-line flag that enables or disables debug output.
  • Error exits are exit(x) where x > 0. exit(0) is for all-ok exits.
  • Size-defined datatypes:
    uint8_t 8-bit unsigned integer
    uint16_t 16-bit unsigned integer
    uint32_t 32-bit unsigned integer
    int32_t 32-bit signed integer

    If available, use the standard header files <stdint.h> or <inttypes.h>.

  • No embedded constants for lengths of buffers. All such lengths should be compile-time constants (e.g., 4000 in audio.c).
  • Compile-time constants are written in UPPERCASE.
  • Programs should use getopt to parse command line arguments, even if you don't have -x style arguments initially. You will, sooner or later. If arguments are required and none are provided, the program should print out usage information, similar in style to the following:
    Usage: cat [OPTION] [FILE]...Concatenate FILE(s), or standard input, to standard output.  -A, --show-all           equivalent to -vET  -b, --number-nonblank    number nonblank output lines  -e                       equivalent to -vE  -E, --show-ends          display $ at end of each line  -n, --number             number all output lines  -s, --squeeze-blank      never more than one single blank line  -t                       equivalent to -vT  -T, --show-tabs          display TAB characters as ^I  -u                       (ignored)  -v, --show-nonprinting   use ^ and M- notation, except for LFD and TAB      --help               display this help and exit      --version            output version information and exitWith no FILE, or when FILE is -, read standard input.
    The usage of longer parameter (with double-dashes) is optional and needed only if you have lots of parameters.
  • Global variables should be marked static unless they are global beyond the file.
  • Standard syntax for system error handling:
      if ((s = foo(y,z)) < 0) {    perror("foo");   /* actually, this should be error function */    exit(1);  }
  • All but trivial projects should be maintained with CVS.
  • In a larger system, functions that are likely useful elsewhere should be separated into a utility directory.
  • Avoid bzero, use memset instead.
  • Use local libraries for the following standard functions:
    • host name lookup: host2ip()
    • event handling: notify.c
    • timers: multimer.c
    • audio I/O
    • hash: Tcl hash

Java Coding Conventions

Java coding conventions:
  • Use javadoc style comments.
  • Do not put tabs in the code. Use spaces.

How To Write Unmaintainable Code

Tcl/Tk Coding Conventions

summary of conventions (Xiaotao Wu, Oct. 2000)
Last updated 03/02/2006 10:15:53 by Henning Schulzrinne