LCLS Controls

C Coding Standards

Quick links:

A. Scope

This page defines C coding standards for the LCLS project. Most of the standards come directly from the requirements in the ESD software SLC ANSI C Coding Standards. Exceptions to these standards are allowed when necessary. In particular, standards are relaxed when the file is a copy from a collaboration and only minor changes are made or when the file will be made available to a collaboration which has its own style or standards.

Every file shall be informally reviewed by a peer.

B. Good Coding Practices

It is assumed that all code shall execute efficiently, not leak memory, allow for performance measurement, minimize global variables, minimize recursion, be well-commented, and be as posix as possible. The README file at the top level level directory of where the source files reside should have a brief description, reference the design documentation and home web page, and contain other helpful build and usage information.

Facilities programmed in C shall manage resources and threads using recommendations in Diane Fairley's Review of Epics Libraries and Resource Usage. For debugging, C files may use the debugging scheme described in $EPICS/site/include/debugPrint.h.

Access to memory-mapped resources that are not ordinary memory (e.g., device registers) shall always be performed explicitly by means of appropriate wrapper headers and/or libraries. Direct register access shall be strongly discouraged. VME memory access (and endian conversion/test) routines developed by Till Straumann are available in $EPICS/site/include/basicIoOps.h and use __iobarrier() assembly instructions on architectures where it is appropriate (PowerPC). Coders should always use the following for programming device IO (even for 8bit IO):

in_le32(), in_be32(), in_le16(), in_be16, in_8(),
out_le32(), out_be32(), out_le16(), out_be16, out_8().

PIO to/from VME is _very_slow_ due to the slow VME bus and the complex protocol transactions through two bridges. If larger amounts of data (>20 words, i.e. VME cycles) need to be transferred, using the DMA engine shall be considered. Otherwise, performance and latencies seriously suffer. A driver/wrapper for DMA is available in the drvUniverseDma library under $EPICS/site with the routines listed in $EPICS/site/include/drvUniverseDma.h. Read operations are slower than writes because the latter can be asynchronous (AKA 'posted'/'decoupled' writes). Note that a read cycle from VME takes 1-2 MICROseconds, effectively blocking the CPU for hundreds of cycles!

C. File, Function, Variable, and Macro Names

  1. The names of all global functions in a multi-function file shall start with the file name.
  2. A global variable name shall start with either the file name that declares it or the facility name.
  3. Separation between subnames in a name shall be accomplished using either upper/lower case or underscores.
  4. Names shall be unique enough so that searching will not find too many hits that don't apply. Distinct names shall differ by more than merely case.
  5. For searchability, more than one character shall be used to name a loop index or subscript.
  6. No variable name shall be greater than 20 chars.
  7. All macros and constants defined using the #define keyword shall be all upper case and shall start with the file or facility name.
  8. File extensions shall be ".c" for source files and ".h" for include files.
  9. Variable names shall not be the same as or similar to keywords.
  10. Variables of fundamental types or primitives (int's, float's, char's) do not need suffixes in their names. However, complex variables shall use the following suffixes:
    "_u" - union
    "_e" - enumeration
    "_s" - structure
    "_c" - null terminated character string
    "_p" - pointer to a primitive
    "_a" - array of primitives
    "_au", "_ae", "_as", "_ac", "_ap" - array of complex variables
    "_pu", "_pe", "_ps", "_pc", "_pa" - pointer to a complex variable
    "_pp" - pointer to a pointer to a primitive
    "_ppu", "_ppe", "_pps" - pointer to a pointer to a complex variable
  11. Typedefs shall use the following suffixes:
    "_t" - typedef of a primitive
    "_tu", "_te", "_ts", "_tc", "_ta" - typedef of a complex variable

D. File Organization

Each file shall be organized as follows:
  1. Standard file header
  2. #include file statements
  3. #define preprocessor statements
  4. File scope data declarations and function prototypes
  5. Standard function header
  6. Function declaration
  7. Function local data declaration
  8. Separation between local data and executable statements (blank lines or a comment line)
  9. Executable statements with comments
  10. Items 5, 6, 7, 8, 9 repeated for each function in the file
  11. If there is only one function in the file, then the standard file header and the standard function header may be combined.
  12. In general, each line in the file shall not be so long that it wraps when printed out.

E. Function Definition

  1. All functions shall have a prototype. Each function argument shall be explicitly declared in the function prototype. The void keyword shall be used when there are no arguments or if the function provides no return.
  2. In general, ordering of function arguments shall be input arguments first, input/output arguments second, and output arguments last.
  3. For readability, the number of indentations in a function shall be limited. To minimize indentations, multiple return statements in a single function shall be used for failure exits.
  4. The goto statement shall only be used on failures when cleanup is required. Only the "egress:" label on the goto shall be allowed. After "egress:", the code shall just cleanup, set status, and return.
  5. The same block of code of significant size shall not be reproduced (cut and pasted) in the same function or group of functions or between files with similar functionality. Shared utility functions shall be developed and used instead.

F. Declarations

  1. Only one data declaration per line shall normally be allowed. An exception would be trivial loop indices. Each data declaration shall be followed by a very short comment describing its use. Similar variables may be grouped together.
  2. Variables local to the function shall be declared only once. Variables shall not be declared within executable statements.
  3. The #define keyword shall be used for constants and macros. All attributes such as accuracy, convergence, timing, buffer sizes and other quantities that are subject to change shall be specified as named #defines. When the #define is used for more than a simple constant, the definition shall be enclosed in parenthesis.
  4. The keyword "const" shall be used in all declarations where appropriate.
  5. With the exception of loop indices, variables shall be used only for one functional purpose.

G. Include Files

  1. Include files shall contain data definitions and parameters that are shared between files. The standard include file header shall be used.
  2. External function prototypes for a multiple-function file shall be kept in one publicly-available include file. Structures, defines, and extern global variables which are a part of the public interface may also reside in the same public include file as the public prototypes or may be kept in a separate public include file(s). The name of all public include files associated with just one C file shall start with the same name as that C file. The name of public include files associated with multiple C files shall start with the facility name. Public include files shall not contain structures, defines, declarations, or prototypes which are file-scope or private to a limited number of closely related files.
  3. All other include files which are needed for the compilation of an include file shall be included in the include file.
  4. Include files shall contain protection against multiple inclusion by checking if a guard macro is defined at the beginning of the file.
  5. Public include files shall check for "__cplusplus" to add "extern "C" {" as necessary to allow inclusion by C++ files.

SLC-Aware IOC Home Page | LCLS Controls | SLAC Computing | SLAC Networking | SLAC Home

Contact: Stephanie Allison
Last Modified: Jun 17, 2005