
http://v2ma09.hst.nasa.gov/coding_standards.html
This document is organized into four sections:
The
symbol is used to denote language specific information. Within tables,
"n/a" denotes "not applicable".
| File contents | C | C++ | Java |
|---|---|---|---|
| class declaration (header) | n/a | X | n/a |
| class definition (source) | n/a | X | X |
| main function | X | X | (with primary class) |
| function(s) | X | X | n/a |
| globals | X | X | n/a |
| File contents | C | C++ | Java |
|---|---|---|---|
| prolog | X | X | X |
| package imports | n/a | n/a | X |
| system #includes | X | X | n/a |
| application #includes | X | X | n/a |
| external functions | X | X | n/a |
| external variables | X | X | n/a |
| constants | X | X | X |
| static variable initializations | X | X | X |
| class declaration | n/a | n/a | X |
| public methods | n/a | X | X |
| protected methods | n/a | X | X |
| private methods | n/a | X | X |
| functions | X | X | n/a |
| File contents | C | C++ | Java |
|---|---|---|---|
| file guard | X | X | n/a |
| prolog | X | X | n/a |
| system #includes | X | X | n/a |
| application #includes | X | X | n/a |
| #defines | X | X | n/a |
| macros | X | X | n/a |
| external functions | X | X | n/a |
| external variables | X | X | n/a |
| constants | X | X | n/a |
| structs | X | X | n/a |
| forward declarations | X | X | n/a |
| class declaration | n/a | X | n/a |
| public methods | n/a | X | n/a |
| protected methods | n/a | X | n/a |
| private methods | n/a | X | n/a |
| inline method definitions | n/a | X | n/a |
| functions | X | X | n/a |
#ifndef MeaningfulNameH // first line of the header file #define MeaningfulNameH // second line of the header file . . // body of the header file . #endif // MeaningfulNameH // last line of the header file; note comment
| Identifier | C | C++ | Java |
|---|---|---|---|
| package | n/a | shortname | |
| class, union, struct | MeaningfulName | ||
| exception class | n/a | MeaningfulException | |
| interface | n/a | MeaningfulActionable | |
| typedef | MeaningfulName | n/a | |
| enum | n/a | MeaningfulName | n/a |
| function, method | meaningfulName | ||
| accessor method | n/a | getX, setX | |
| object, variable | meaningfulName | ||
| #define, macro | MEANINGFUL_NAME | n/a | |
| const, static final variable | MEANINGFUL_NAME | ||
| source file | .c | .cpp | .java |
| header file | .h | n/a | |
Names should be readable and self-documenting. Abbreviations and contractions are discouraged. Shorter synonyms are allowed when they follow common usage within the domain.
All names should begin with a letter. Individual words in compound names are differentiated by capitalizing the first letter of each word as opposed to separating with an underscore. The use of special characters (anything other than letters and digits), including underscores is strongly discouraged. The first 31 characters of a name (including the prefix) must be unique, due to restrictions of various platforms. The uniqueness must not be due solely to a difference in case.
Filenames should only contain one period, to separate the file extension.
Function names should preferably be an action verb. Boolean-valued functions (those that have two possible return values) should use the "is" prefix as in "isEmpty()".
Namespace collision should be minimized without introducing cryptic
naming conventions by using the C++ namespace
or Java package constructs.
cout << "This is an example of a line which must be wrapped, value = "
<< value << endl;
/**
* This is a module, class, function, or instance variable comment
* that will be extracted by an automated documentation tool.
*/
This will provide a consistent look across all source code files, and
should facilitate creation of automated documentation tools.
Such comments should be used to describe classes, methods, and global or instance variables.
/* and */.
//.
() or non-dimensioned arrays [].
::.
. and ->.
if ( value == 0 ) { // right
if (value==0){ // not recommended
void doIt( int v ); // right
void doIt(int v); // not recommended
value = object->GetValue(); // right
value=object -> GetValue(); // wrong
int main() {
doSomething();
}
struct MyStruct {
int x;
int y;
}
if ( value == 0 ) {
doSomething();
} else if ( value == 2 ) { // note position of cascaded if statement
doSomething2();
} else {
doSomething3();
}
while ( value < 300 ) {
doSomething();
}
do {
doSomething();
} while ( value < 300 ) // note: ending brace and control on same line
switch ( value ) {
case 1:
doSomething();
break;
case 2:
case 3:
doSomething2();
break;
default:
break; // final break required
}
* and the
address-of operator & placed adjacent to the type, not the variable.
For example:
char* text; // right char *text; // not recommended char* doSomething( int* x ); // right char *doSomething( int *x ); // not recommended
if ( value == 0 ) { // right
doSomething();
}
if ( value == 0 ) doSomething(); // wrong - no block, not indented
if (value == 0)
doSomething(); // wrong - no block
if, while, and
do statements should be explicit based on the data type of the
variable being tested. For example:
int value = getValue();
if ( value == 0 ) { // right
doSomething();
}
if ( !value ) { // wrong - not explicit test
doSomethingElse();
}
boolean value = getValue();
if ( !value ) { // right - this is explicit
doSomethingElse(); // test for boolean type
}
#include statements should be
grouped together at the top of the file after the prolog. Includes should be
logically grouped together, with the groups separated by a blank line. System
includes should use the <file.h> notation, and all other
includes should use the "file.h" notation. Path names should
never be explicitly used in
#include statements (with the exception of vendor library files
such as Motif), since this is inherently non-portable.
For example:
#include <stdlib.h> // right #include <stdio.h> // #include <Xm/Xm.h> // #include "meaningfulname.h" // #include "/proj/util/MeaningfulName.h" // wrong - explicit path, #include <stdlib.h> // out of order, #include </usr/include/stdio.h> // path for system file, #include "Xm/Xm.h" // local include of library file
int* a; // right int b; // int c; // double d; // double e; // double a; // right int b; // double d; // acceptable - not grouped by type int b; // int* a; // double e; // int c; // int* a, b, c; // wrong - not individually declared, not // on separate lines int* a, // wrong - not individually declared b, // c; //The two preceding examples are prone to error; notice that
a is
declared as a pointer to integer and b and c are
declared as integers, not as pointers to integers.
In the header file MeaningfulName.h,
#ifdef MeaningfulNameInit // the flag is called MeaningfulNameInit #define EXTERN // create the variable (only in main.cpp) #else #define EXTERN extern // just a reference (default) #endif EXTERN ErrorLogger errorLog; #undef EXTERNAll of the source files should include this header file normally:
#include meaningfulname.hwhile the following should appear only in the source file where you actually want to declare the variable and allocate memory for it (typically in
main.cpp):
#define MeaningfulNameInit #include meaningfulname.h #undef MeaningfulNameInit
const int value = A73B2X; // right, hexadecimal constant const double evalue = 1.2E9; // right, scientific notation constant const float fvalue = 1.2e9; // wrong, lowercase e
enum type name and enumerated constants should each reside
on a separate line. Constants and comments should be aligned
vertically. Following is an example of a valid enum declaration:
enum CompassPoints { // Enums used to specify direction.
North = 0, //
South = 1, //
East = 2, //
West = 3 //
};
struct type name and structure members should each reside on a
separate line. This format separates the members for easy reading, is
easy to comment, and eliminates line wrapping for large numbers of members.
Each struct should have a one-line description on the same line
as the type
name. Each member should have a comment describing what it is, and units if
applicable. Members and comments should be aligned vertically. Following is
an example of a valid struct declaration:
struct MeaningfulName { // This is a struct of some data.
int firstInteger; // This is the first int.
int secondInteger; // This is the second int.
double firstDouble; // This is the first double.
double secondDouble; // This is the second double.
};
{}
or { return x; }) may be defined within the declaration itself.
Each member
function and variable should be commented using the automated documentation
comment delimiter /**. Member functions should be
commented in the same fashion as a regular function. Member variables
should each have a one line description. Members and comments should be
aligned vertically. For example:
class Value : public BaseValue {
public:
Value(); // Default constructor.
Value( const Value& oldValue ); // Copy constructor.
~Value(); // Destructor.
void setValue( int newValue ); // Set value.
int getValue(); // Get value.
protected:
void incrementValue(); // Increment value.
private:
int value; // The value.
};
case block, including the last
one. It is recommended that a default case always be defined.
return from a function or method
as the last statement. Otherwise,
minimize the number of returns. Highlight returns with
comments and/or blank lines to keep them from being lost in other
code.
const double PI = 3.141259; // right const char APP_NAME = "ACME Spreadsheet 1.0"; // right area = 3.141259 * radius * radius; // not recommended cout << "ACME Spreadsheet 1.0" << endl; // not recommended
The use of #define constants is strongly discouraged, using
const is recommended instead.
The use of #define macros is strongly discouraged, using
inline functions is recommended instead.
The use of typedef is strongly discouraged where actual types
such as class, struct, or enum could
be used instead.
The use of extern (e.g., global) variables is strongly discouraged.
The exception is
for programs which benefit from having a small number of object
pointers accessible globally via extern.
The use of goto statements is not allowed.
#define MAX( x, y ) ( (x) > (y) ) ? (x) : (y) )
#ifdef compile-time
switches. The symbols to use are DEBUG and STATS,
respectively. Debug
statements announcing entry into a function or member function should
provide the entire function name including the class. For example:
#ifdef DEBUG
cout << "MeaningfulName::doSomething: about to do something" << endl;
#endif
new and delete instead of
malloc/calloc/realloc and free. Allocate
memory with new only when necessary for variable to remain after
leaving the current scope. Use the delete [] operator to
deallocate
arrays (the use of delete without the array operator
to delete arrays is undefined). After
deletion, set the pointer to zero, to safeguard possible future calls
to delete. C++ guarantees that delete 0 will be
harmless.
MyClass();) defined. Providing a deep copy constructor is
strongly recommended.
const reference. If the argument will be modified, pass by reference.
For example:
void A::function( int notChanged ); // default: pass by value void B::function( const C& bigReadOnlyObject ) // pass by const reference void C::function( int notChanged, int& result ); // pass by reference
const. This allows these
functions to be called for objects which were either declared as
const or passed as const arguments.
extern "C" mechanism to allow access to non-C++ (not just
C) functions. This mechanism disables C++ name mangling, which allows the
linker to resolve the function references. For example:
extern "C" {
void aFunction(); // single non-C++ function prototype
}
extern "C" {
#include "functions.h" // library of non-C++ functions
}
NULL macro for initialization,
assignment, and comparison of pointers. The use of NULL is not
portable, since different environments may define it to be something
other than zero (e.g., (char*)0).
endl to terminate an output line,
instead of the newline character \n. In addition to being more
readable, the endl manipulator not only inserts a newline
character but also flushes the output buffer.
public.
Open access to
internal variables exposes structure and does not allow methods to assume
values are valid.
Class.newInstance(). This
exploits the power
of Java to dynamically link in functionality that was not present at compile
time.
Last update November 1, 1996 by Jeff Johnson jjohnson@v2pop.hst.nasa.gov