From RTSC-Pedia

Jump to: navigation, search
revision tip
—— LANDSCAPE orientation
[printable version]  [offline version]offline version generated on 04-Aug-2010 21:08 UTC

RTSC Coding Conventions

Coding conventions used in the XDCtools product

Contents

Introduction

This coding conventions document contains the standard conventions that are followed by the XDCtools development team and that we recommend that others follow. It covers naming conventions, physical design, declarations, and programming practices. Code conventions are important to programmers for a number of reasons:

  • 80% of the lifetime cost of a piece of software goes to maintenance.
  • Hardly any software is maintained for its whole life by the original author.
  • Code conventions improve the readability of the software, allowing engineers to understand new code more quickly and thoroughly.

Naming Conventions

All of the modules, interfaces, and packages in XDCtools follow a set of naming conventions that improve the readability of the sources and enable common questions about the source to be answered without the aid of a tool (e.g., etags). The benefits of these conventions are as follows:

  1. Package names can be distinguished from module names. For example, ti.bios.utils is a package, but ti.bios.Utils is a module in the ti.bios package.
  2. Modifiable entities can be distinguished from constants. For example, System.DONE is a constant, but System.maxPasses is a module configuration parameter.
  3. Interfaces can be distinguished from concrete modules. For example, xdc.IPlatform is an interface, but xdc.Platform is a module.
  4. Types can be distinguished from variables and functions. For example, String and Startup_InitFxn are types, but arg and Startup_firstFxns are parameters or variables.


Identifier Naming Conventions
Convention Examples
Package names are all lowercase. xdc.runtime
Packages that are expected to be referenced by content produced by other groups should have globally unique names. ti.targets.arm
Module names begin with an uppercase letter. xdc.runtime.Memory
Interface names begin with an uppercase "I". IHeap and IGateProvider
Type names begin with an uppercase letter. The uppercase applies to the first letter after any package or module prefix; for example, "Handle" in Task_Handle and ti_sysbios_knl_Task_Handle. IArg, String, and xdc_String
Multiple-word identifiers are separated by uppercase letters, not an underscore. Mod_twoWords
Constants are in all uppercase after the module or package prefix. If multiple words are required, an underscore delimits the words. Diags_INTERNAL and Types_STATIC_POLICY
Structure field names and configuration parameters begin with a lowercase letter. attrs.count and System_maxAtexitHandlers
Functions, variables, and parameter names begin with a lowercase letter after any module prefix. Camel case is used where needed to delimit multiword names. Diags_setMask() is a function and Log_system is a global variable

In order to ensure that packages can be created/developed/delivered independently (with no centralized control) it is important that no two packages have the same name; otherwise a client will be forced to use just one of the packages. This requirement may be relaxed in cases where there is no expectation that a package will be used with other packages (such as self-contained examples).

With the exception that we do not require package names to include the top-level domain names (e.g., com, edu, gov, org, ...) of the company's URL, the naming conventions are consistent with the Java naming conventions specified by SUN (http://java.sun.com/docs/codeconv/). However, using a company's URL followed by division, department, and project is a convenient way to ensure globally unique package names.

Data Types

XDCtools defines the following base datatypes for use in C code in xdc/std.h. You should use these types in application code that uses RTSC modules or is intended to be portable to multiple targets. Most datatypes have names that are similar to the corresponding C type, but with titleCase used for differentiation and abbreviation of unsigned and long. The underlying sizes may be different on various targets. For more information about these types as well as predefined macros that facilitate the creation of portable C modules see the reference documentations for the xdc package.

Portable Data Types
RTSC Type C99 Type Comments
Bits16 uint16_t not supported on some targets; e.g., TI's C30 and C40 targets
Bits32 uint32_t may not be supported on some targets
Bits8 uint8_t not supported on some targets; e.g., TI's C28, C30, C40, C54, and most C55 targets
Bool unsigned short 1 for true and 0 for false or use TRUE and FALSE
Char char
Double double
Float float
Fxn int (*)() generic function pointer
IArg intptr_t signed argument large enough to hold an int or any pointer type
Int int
Int16 int_least16_t or int_fast16_t the target may opt to use either the int_fast or the int_least types for these definitions.
Int32 int_least32_t or int_fast32_t
Int8 int_least8_t or int_fast8_t
LDouble long double
LLong long long may be supported only as long on some targets
Long long
Ptr void* data pointer
Short short
SizeT size_t
String char* null-terminated string
UArg uintptr_t unsigned argument large enough to hold an int or any pointer type
UChar unsigned char
UInt unsigned int
UInt16 uint_least16_t or unint_fast_16_t the target may opt to use either the uint_fast or the uint_least types.
UInt32 uint_least32_t or unint_fast32_t
UInt8 uint_least8_t or unint_fast_8_t
ULLong unsigned long long may be supported only as unsigned long on some targets
ULong unsigned long
UShort unsigned short
VaList va_list

Physical Design

  1. all package names must match the installation directory of the package; e.g., the package xdc.runtime must be in a directory that ends with xdc/runtime/.
  2. all module interface headers must be contained in the package's base.
  3. File names within a package must never have names that differ only in letter-case.
  4. Each "component" of a package name (i.e., sequence of characters between '.'s) must only contain characters allowable in C identifiers and must not be a C/C++ keyword ("if", "then", "switch", ...) or "package".
  5. All references to package and modules must match the case of the package and module names.

Rationale

The RTSC package physical design rule is the same as that imposed by Java for Java packages. While we may not be interested in supporting Java directly, it is clearly a scalable design that is well supported by tools; thousands of Java packages are developed, deployed, and reused by a similar number of separate development groups.

In addition, this simple physical design rule - that a package's name must match the installation directory - allows us to integrate virtually all existing command line tools (e.g., C/C++ compilers, linkers, GNU make, ...) without requiring any change on their part. Any command line tool that accepts a '-I' type of option for locating include files can be seamlessly integrated into a RTSC development environment by simply adding a -I option for each element of the RTSC package path to each command line tool. In this way, we ensure that all files for all tools are always found along the package path.

Constraining all top-level interface headers to be in the package's base enables the client to follow a single simple procedure for using a new module from a new package:

  1. add a #include in any referencing source of the form: #include <pkg_name/mod_name.h>
  2. call the module's functions

In addition, during reviews of source, it is easy for the client to quickly identify all external package dependencies and answer the question, "Where is the xyz function/constant/type defined?".

Keeping package names in lower-case together with the convention that all modules are title-case makes it easy for the developer to clearly see the difference between a package reference such as "xdc.services.utils" containing a module named "xdc.services.utils.Load" and a module reference such as "xdc.services.Utils".

Since package names are used in C/C++ source to reference include files and appear in module methods names, it is important that only valid C identifiers be used in each component of a package name. For the same reason, "components" of package names can not be C keywords; e.g., if, while, switch, ...

Although Windows file-systems do not distinguish file name references that differ on in case, Unix file-systems do and most languages do. To ensure host development system portability, it is important that all references strictly match the case of the referenced file. In addition, to ensure that packages are host OS independent, it is important that no two files have the same name except for letter-case. For example, it is not possible to have both "Makefile" and "makefile" in the same directory on a Windows host. So even though this can be supported on Linux hosts, the requirements above prohibit packages from having two such files.

Module and Interface Conventions

This section contains conventions followed when creating a module or an interface.

Header Conventions

This section covers conventions required by all "hand crafted" C/C++ header files.

Doxygen Conventions

NOTE:  to be written

XDoc Comments


   /*!
     *  ====== getFoo ========
     *  Return the current foo
     */
    Foo getFoo();

  • All methods must provide summary XDoc documentation for all parameters, return values, and exceptions.
  • All summaries should be short and must never be more than one line.

    /*!
     *  ======== alloc ========
     *  A method summary
     *
     *  A long description goes here.
     *
     *  @param(heap)    summary comments without period at the end of the line
     *  @param(size)    summary comments
     *  @param(align)   summary comments
     *
     *                  Longer descriptions of parameters are placed here.  Notice
     *                  the blank line separating the summary and this longer 
     *                  description.
     *
     *  @param(eb)      pointer to error block
     *
     *  @a(returns)
     *  The name of the return section is "returns" and the description consists of
     *  complete sentences.
     *
     *  No returns section is required for methods that do not return a value.
     *
     *  @a(throws)
     *  The name of the exceptions section is "throws" and all possible exceptions 
     *  should be enumerated here with a brief description how what can cause the exception.
     *  @p(dlist)
     *  - CorruptHeap
     *    Underlying heap data structures have been corrupted.
     *  @p
     */
    Ptr alloc(IHeap.Handle heap, SizeT size, SizeT align, Error.Block *eb);

  • All methods, structures, types, must include a summary XDoc comment. Summary comments need not be complete sentences. However, all description sections should consist of complete sentences.
  • Summary XDoc comments must be less than one line (< 80 characters, including any banner comment prefix characters). Longer comments should be part of the optional description XDoc comments.
Wrong:

    /*!                                                                         
     *  ======== foo ========                                    
     *  This assert is thrown when a frabazfoo is not the same as the expected flabazfoo.  If
     *  this assert occurs call for help.                                       
     */
    config Assert.Id foo = ...;

Right:


    /*!                                                                         
     *  ======== foo ========                                    
     *  Assert that the frabazfoo is the same as the flabazfoo      
     *                                                                          
     *  This assert is thrown when a frabazfoo is not the same as the expected flabazfoo.  If
     *  this assert occurs call for help.                                       
    */
    config Assert.Id foo = ...;

  • All fields within a structure should have an in-line summary comment.

    /*!                                                                         
     *  ======== MyStruct ========                                    
     *  A useful structure                    
     */
    struct MyStruct{
        Int aField;  /*! a short summary comment */
    };

  • Fields within a structure that require longer descriptions should include @field tags in the structure's description.

    /*!                                                                         
     *  ======== MyStruct ========                                    
     *  A useful structure
     *
     *  @field(aField) This field is so rich that it requires a detailed description
     */
    struct MyStruct{
        Int aField;  /*! a short summary comment */
    };

  • When in doubt, follow corresponding JavaDoc guidelines described by SUN: doc comments.

Lexical Conventions

The lexical conventions in this section apply to C and C++ sources and (unless otherwise noted) all C-like source languages including Java and JavaScript.

Expressions

  • No space exists between unary operators or between the primary operators ->, ., [], and () and their operands. Note that sizeof is a unary operator.
Unary operator examples:

    i++
    !e
    (Char *)p
    -17
    sizeof(Int)

Primary operator examples:


    a[i]
    s.member
    p->member
    f(x, y)

  • There is exactly one space between other operators and their operands. For example, binary operators are used in the following examples:

    x = f(y) * (z + 2);
    p != NULL && (p->member == -1)

  • Parentheses are used for clarity, especially in expressions involving several precedence levels. For example:

    x < y & mask   /* WRONG! */
    (x < y) & mask /* RIGHT */

  • Unless explicitly defined by the C language, evaluation order is not relied upon.
  • Expressions with side effects are not used in function calls. This is because the function may be changed to a macro at some point.

    t = min(x++, y); /* WRONG! */
    t = min(x, y);   /* RIGHT */
    x++;

  • When breaking long expressions into more than one line (e.g., to satisfy the 80-character line length limit), the beginning of each new line should begin with an operator.

    /* WRONG! */
    if (xdc_runtime_TimestampStd_getFreq(&myVeryDescriptiveNameForFrequency) <
        32) {
           :
    }

    /* RIGHT! */
    if (xdc_runtime_TimestampStd_getFreq(&myVeryDescriptiveNameForFrequency)
        < 32) {
           :
    }

Statements

  • All subordinate statements are enclosed in braces and indented four (4) spaces.
  • There is exactly one statement per line.
  • Continuation lines are indented eight (8) spaces

The following examples show how certain types of statements should be formatted:

  • Do statement

    do {
        stmt(s);
    } while (expr);

  • For statement:

    for (expr; expr; expr) { /* note space after ';' */
        stmt(s);
    }

  • If statement:

    if (expr) {
        stmt(s);
    }

  • If-else statement:

    if (expr) {
        stmt(s);
    }
    else {
        stmt(s);
    }

  • If-else if statement:

    if (expr) {
        stmt(s);
    }
    else if (expr) {
        stmt(s);
    }
    else {
        stmt(s);
    }

  • Return statements

    return (value); /* note space and parens */

  • Switch statement:

    switch (expr) {
        case CONST: /* note indentation */
            break;

        case CONST: /* note space between case arms */
            break;

        default: {  /* always present, even if null */
            break;
        }
    }

  • While statement:

    while (expr) {
        stmt(s);
    }

  • try-catch blocks

    try {
        :
    } 
    catch (...) { /* as with if statements, always use {}'s */
        : 
    }

Declarations

  • Each variable or member is declared on a separate line.
  • All internal source-file variables and functions are declared as static.
  • Module-wide declarations appear in the following order:
    1. constants
    2. types
    3. variables
    4. functions

Function Definitions

  • Prototypes must always be specified.

    Int XXX_open(Char *name, Bool rmFlag) /* RIGHT */
    Int XXX_open(name, rmFlag)             /* WRONG! */
        Char * name;
        Bool rmFlag;

  • Functions should be defined in alphabetical order.
  • For functions with more than one parameter, there is a space between a comma and the type specifier for the next parameter. There is also a space between a comma and an argument in function calls.
  • There is one blank line between the last declaration in the function body and the first statement in the function.
  • Function body braces are aligned with left margin and the body is indented four (4) spaces. For example:

    Void foo(Int bar)
    {
        Int i;

        for(i = 0; i < 10; i++) { /* note the blank line before this */
            :
        }
    }

Macro Definitions

A macro definition must have one of the following forms:

  • A single token:

    #define QUE_enqueue QUE_put

  • A function or macro call:

    #define C62_enableGIE(mask) HWI_restore(mask)

  • Enclosed in parentheses:

    #define C62_mask(devid) ((Uns)(1 << (devid)-1))

  • Enclosed in curly braces:

    #define QUE_remove(elem) {\
        ((QUE_Elem *)(elem))->prev->next = ((QUE_Elem *)(elem))->next; \
        ((QUE_Elem *)(elem))->next->prev = ((QUE_Elem *)(elem))->prev; \
    }

In all cases, each use of a macro parameter must be enclosed in parentheses. For example, see the uses of "elem" and "devid" above.

Comments

  • Border comments begin at column 0 and introduce procedures and major sections. Text for a border comment is indented two spaces and starts on the second line. Border comments appear only between function definitions and never within a function body.

    /*
     *  This is a border comment.
     *  Note the two spaces in from the '*' character.
     */

  • A source file begins with a border comment. This comment should include a revision section with the format shown below. Note that the continuation of a long revision comment is indented by four (4) spaces.

     *! Revision History
     *! ================
     *! 23-Jan-2001 mf: The entire Revision History section must begin with tokens
     *!     that end in an exclamation point, so it can be stripped if necessary.
     *! 24-Dec-2000 mf: Revisions appear in reverse chronological order; that is,
     *!     newest first. The date format is dd-Mon-yyyy.

  • All functions have the following style of banner:

    /*
     * ======== foo ========
     * A one-line summary of the function is placed here.
     *
     * A more complete description optionally follows.  Note the
     * "empty" line separating the summary from this description.
     */
    static Void foo(Int param)
    {
        stmt(s);
    }

Note that the name of the function is placed between two strings of eight (8) consecutive "=" characters and a single space. This banner style makes it easy to find all functions declared in a module.

  • Multi-line comments are formatted as follows. Note that two (2) spaces follow the asterisk.

    /*
     * this is a multi-line indented
     * comment
     */

  • Indented comments introduce blocks of code.

    while (expr) {
        /* this is a simple indented comment */
        if (expr) {
            stmt(s);
        }
        else {
            stmt(s);
        }
        stmt(s); /* this is an in-line comment */
     }

  • In-line comments describe individual statements or declarations. All global variables (static or otherwise), configuration variables, #define constants, and structure members should have in-line or possibly multi-line comments giving their meaning.

    static Int curInit = FALSE; /* XXX_Init was called */
    #define OUTPORT 0xfc000002 /* output port address */
    struct TSK_Attrs {
        Int priority; /* task priority */
    };

  • C++ style comments must not be used in C sources. They may be used in C++, Java, or JavaScript sources.

    while (expr) {
        // this is a simple indented C++ comment
        if (expr) {
             stmt(s); // this is an in-line C++ comment
        }
    }

  • Following Sun's Java conventions, the // comment delimiter can comment out a complete line or only a partial line. It shouldn't be used on consecutive multiple lines for text comments; however, it can be used in consecutive multiple lines for commenting out sections of code. Examples of all three styles follow:

    if (foo > 1) {
        // Do a double-flip.
        ...
    }
    else {
        return false;          // Explain why here.
    }
    //if (bar > 1) {
    //
    //    // Do a triple-flip.
    //    ...
    //}
    //else {
    //    return false;
    //}

Spaces and Tabs

As described above, the standard indentation level is four (4) spaces. The tab character (\t) should be treated as eight (8) space indent. Source code may contain a mix of spaces and tabs, where a tab is equivalent to indent to the nearest eight spaces. Released source code should contain only spaces (no tabs).

Lines should not exceed eighty (80) characters in length. While current editors and UIs allow for much longer lines, most printed material is still eighty characters or less. For publication in manuals, the maximum line length is 74 characters.

Line Termination Format

Unix hosts, Windows hosts and MacOS hosts have differing line termination characters for text files. For consistency and improved portability of the text files that are intended to be used on all development platforms, all "portable" text files should be Unix file formatted.

In other words, unless a file is specifically for use only on a non-Unix host, the file should be Unix file format; each line should be terminated with a single '\n' character (ASCII 0x0a).

Language Specifics

This section describes language-specific conventions that are not covered by other sections of this document.

Java

Imported classes should always be listed explicitly.

    import java.util.List;       // NOT: import java.util.*; 
    import java.util.ArrayList; 
    import java.util.HashSet;

While the use of "*" can be useful when importing classes from a single package, as soon as you import classes from more than one package, it is difficult to know which package defines which class. Importing classes explicitly makes the class easier to comprehend and maintain.

Appropriate tools should be used in order to always keep the import list minimal and up to date.

The Use of goto Statements

Do not use the goto statement when it is possible to use a structured flow control statement to accomplish the same goal. For example, this function below uses a goto statement unnecessarily.


    foo()
    {
        ...
        if ((status = open("foo", 0)) < 0) {
            'clean up';
            goto exit;
        }
        doit(status);
    exit:
        return (status);
    }

This function can be rewritten as


    foo()
    {
        ...
        if ((status = open("foo", 0)) < 0) {
            'clean up';
        }
        else {
            doit(status);
        }
        return (status);
    }

This second form has the advantage that it makes it clear that doit() is only performed when the open() function returns a non-negative result. The undisciplined use of goto statements can result in code that is impossible to read or maintain. There are, however, situations when the goto statement is appropriate and its use actually improves the readability and efficiency of a function. These cases are rare, but the following code fragment shows an example where the use of a goto simplifies the structure.


    {
        /* acquire a lock that must be released before returning */
        seize(lock);
        while (expr) {
            if (open("foo", 0) < 0) {
                goto exit;
            }
            bar();
        }
        stmt(s);
    exit:
        release(lock); /* release acquired lock */
        return (status);
    }

[printable version]  [offline version]offline version generated on 04-Aug-2010 21:08 UTC
Copyright © 2008 The Eclipse Foundation. All Rights Reserved
Views
Personal tools
package reference