//從FDP的文件貼上來的,為了適用於BBS 版面有點亂...
CODING STANDARD for FDP and RELATED PROJECTS
============================================
Author: Kris Vorwerk
Last Update: May 9, 2004
1. Philosophy
=============
- By adhereing to a common coding standard, the code will be legible,
consistent, and easier to debug.
- The coding standard is the definitive guideline. Omissions in the coding
standard should be brought to the attention of the Coding Standard
Maintainer, who will subsequently revise the appropriate section of the
standard and advise the programmer with respect to the ambiguity.
2. Language
===========
- The programming language is, at all times, expected to be C++, unless and
until the day comes that there exists a faster, better, more accepted
programming language.
- An object-oriented paradigm using the C++ Standard Template Libraries (or
Boost) should be employed. No programmer shall implement their own
container class or algorithm if such a container class is proven to exist
in the STL.
3. Application Layout
=====================
- The structure of the code is expected to (roughly) follow the following
directory layout:
./doc
./etc
./src
- Source code files should be labelled "cleanly" such that their filenames
convey the true nature of the contained code. (I would expect that the
contained code would also have a class labelled similarly to the filename.)
4. Functions
============
- Classes are to be used to encapsulate functions, as often as possible.
- Public classes are to be defined in their own header file, with generally
one class per file. The code corresponding to the classes are to go in
their own (similarly named) source code file. Names of classes must, at all
times, be capitalized.
- Functions are to be grouped by those that are public and private, and are
to be listed in the source and header files in alphabetical order. Public
functions use capital first letters. Private functions use lower case first
letters.
- Function names generally don't contain underscores -- rather, we use
capital
letters to create the names. For example, based on our naming guidelines,
we would name a private function of class Foo as:
void Foo::getNumberOfLines( uint32 i )
- Section labels -- lines drawn across the screen (up to the 78th column)
are
to be used to distinguish between various parts of the header or source
files. These lines make an attractive (and noticeable) differentiation
between the public and private functions, for example.
- Do not use the 'inline' keyword until after you have written your code.It
should only be inserted during the final debugging and tweaking of a piece
of code.
- Small functions (ones that can be inlined -- only a few lines), and that
make sense to do so, should be put in the header file of the class in
question. Some functions have to be placed in the header files to ensure
proper inter-library operation, sometimes, too.
- Functions that accept no arguments should have the "void" keyword
explicitly written in the function's prototype.
e.g., void Foo::calculateArea( void )
{
...
}
- Functions that do not modify the contents of a class should have the
'const' keyword appended at its end.
- Your classes should always have a constructor and destructor declared.
(Even if the ctor/dtor do *nothing*, they should still be declared.)
5. Variables
============
- There should be only one global variable in a program -- the singleton
class
called "Program". All globally accessible variables or objects are to be
made members of this class. Otherwise, all other variables are to be kept
as members of their respective classes.
- Variables follow the general naming convention of functions. Global
variables have capital names. Member variables of classes and structures
are to begin with the "_" character. For example: "uint32 _member"
declares an unsigned, 32-bit integer named "_member".
- Try to refrain from using 'int', 'short', and 'char' for 32-bit, 16-bit,
and 8-bit values. We use 'uint32' to designate unsigned 32-bit integers,
and sint32 as its signed counterpart. Similarly for uint16, uint8, etc.
We use 'real32' in place of 'float' and 'real64' in place of 'double'.
Since 'long double' is not portable to all platforms, I discourage the
use of a type named 'real128'.
- Make use of tabs to align variable and function names neatly.
Example:
class Foo
{
public:
vector<double> & GetVec( void );
private:
uint32 calculate( void );
public:
long double _myDouble;
private:
char * _string;
};
Notes on this example:
- observe the tab-aligned variable names and functions
- observe that public functions are first, then private
functions, then public variables, then private variables
- observe the use of capitals for public functions and
lower-case for private functions
- observe the "_" that preceeds variable names
- observe the brackets and bracket spacing
- The issue of keeping members of a class private, and accessing them only
through public member functions is a sticky one. At one time, doing this
(and making functions that Get() or Set() each of the variables) was
considered the appropriate way of coding C++. Now, however, the accepted
philosophy is that, if a variable should be accessed directly, then let it
be access directly. (This is the philosophy adopted by the C++ STL and by
its creator, Alexander Stepanov.) In keeping with this rule, this coding
standard specifies the following rules:
* Only use Get() or Set() methods to access member variables if the
respective Get() or Set() performs something intuitively
non-obvious.
* Do not use Get() or Set() to simply return a member variable's
value; instead, make the member variable public and access it
directly, like you would access the 'first' or 'second' members of
the STL "map" class.
* Example:
class Foo
{
public:
float GetArea( void )
{
return _width * _height;
}
public:
float _height;
float _width;
};
Notes on this example:
- observe the spacing with the brackets
- observe the use of the underscore
- observe the use of a separate "public" section devoted
solely to the variables in the class
- observe the use of tabs to distance the variable names
from the variable type (using tabs in this way can make
the class declaration look much nicer)
- observe the use of a non-intuitive Get() function, versus
simply allowing the base _height and _member variables to
be accessed directly
6. Spacing and Brackets
=======================
- Consistent spacing is vitally important to good code readability. The
format that we have adopted in this project uses spaces after beginning
parentheses and before the ending parentheses. Brackets for if, for, while,
etc. are to appear on the same line. Case values for switch statements are
to appear on the same line as the switch. Examples of these rules are
provided for reference:
for( i = 0; i < foo; ++i ) { and NOT for(i = 0; i < foo;++i)
... {
} ...
}
if( true ) {
...
}
switch( bar ) { and NOT switch( bar ) {
case 0: case 0:
break; ...
case 1: }
...
}
- Brackets that follow structures, classes, and functions should not
be on the
same line as the declaration name (unline if, while, for statements).
Thus,
a correct function declaration would look like:
void Foo::bar( int a ) and NOT void Foo::bar (int a) {
{ ...
... }
}
- Do not use spaces to indent your work. Use tabs. (Generally, the code
should look correct when the tab width is set to '8'.)
- A good GNU 'indent' command line to achieve this spacing is:
indent -br -nsai -nsaf -nsaw -fca -brs -i 8 -lp -kr -nbbo -prs -ut -ts 8
7. Polymorphism, Inheritance, Templates
=======================================
- Avoid polymorphism and inheritance as much as possible. They can be
useful techniques, although the former can incur a performance penalty
and each can obfuscate the code, making it difficult to read. In general,
apply the following rule:
"If a class or set of classes can be coded equally efficiently and
with an equally portable and useful abstraction without
polymorphism or inheritance, then do so. If not, be very careful
what you choose to inherit or make virtual, and at all times keep
in mind the requirements of performance and legibility."
- Given C++'s advancement over the years, templates are now considered
stable
and useable. (There was a time when very few compilers actually handled
templates correctly, and they were shunned by most C++ developers and book
authors.) Now, though, templates work generally as expected. Keep in mind,
though, that templates can lead to code bloat because they may require
multiple instantiations of various containers to handle differences
in the type of object that you pass in the template. Be wary of this
problem. (One way to get around it, if you find yourself in a position
where code bloat may be a possibility, is to declare classes that take
pointers to functions, using the STL's ptr_fun() function.)
8. Miscellaneous
================
- Do not use macros, in general. Use inlined C++ functions.
- Inlined, publically accessible class functions should go in the header
file.
Private (non-public) inlined functions should be declared "inline", and the
code should be inserted into the source file.
- Do not use a postfix increment (i.e., i++) unless you actually need to
read
the value of "i" before it is incremented, as in: node[i++]. If you are
simply specifying a counter, use the prefix notation: ++i.
- When using a switch statement in which one case is purposefully intended
to
fall thru to the next case statement, you should insert a comment to that
effect.
- Write code so that compiler warnings do not exist. If they do exist, it
should only be in code that you are presently debugging -- production
code should, under no circumstances, produce any compiler warnings.
- Write standards-compliant code, always keeping in mind the notion that
the application may be one day ported to a platform with a horribly
pedantic C++
compiler (e.g., AIX). Try to avoid GNU-specific extensions when there
exist equally good POSIX-compliant ways of doing something.
- Document your code. Use C++-style comments for short "bursts"
(up to ~8-10 lines), and only use C-style ( /* */ )
comments for very long sections.
- Encapsulate debugging code within debugging sections (i.e., #if DEBUG ),
and make frequent use of the DEBUG_ASSERT( ) to maintain proper program
behaviour.
- Pay careful attention to the LOG level that you output. Try to adhere to
the general philosophy of DEBUG versus INFO versus NOTICE (etc.) when
selecting the verbosity level of your LOG() command. Do NOT use "cout"
or printf() to output text to the screen.
- Generally, avoid recursive functions. If you must implement recursive
functionality, write it using queues/stacks -- that way, we avoid the
memory penalty that large recursive calls inflicts on the stack.
- Refrain from using C++ exceptions. They can slow down your code, and
really render code indecipherable. While some may argue that this
approach is not good for object orientedness, it is intended to make
things easier to read while still retaining the performance one would
expect when things "go wrong" (i.e., an exception is generated).
- If you are planning on using a straightforward queue, simple performance
tests that I've done indicate that the "deque" class results in 4x faster
code than the "list" class (even though the two can be used in essentially
the same way).
- Performance tests have established the following:
1) If you are doing any kind of sort()ing, do not use a deque. Use
a vector instead.
2) If you know the size of the vector ahead of time, or even if you
know an upper bound to the size of the vector, you should always
call the vector::reserve() function! This will not only
dramatically improve performance but also reduce memory consumption.
3) If you are simply inserting elements into a container, but you know
the size of the container ahead of time, it is faster to use a
vector (whose capacity has been reserve()d) than it is to use a
deque.
4) In other words, ONLY use a deque if you do not know an upper bound
to the size of the container (or the realistic size of the container
is dramatically smaller than its upper bound), or if you absolutely
require queue (push/pop) operations. Otherwise, a vector which has
had the reserve() function called turns out to be much faster both
for inserting and sorting.
- Performance:
Generally, if you need to sort things often, declare a vector
whose size is equal to the maximum possible size. Then, when you
sort, you can do:
std::sort( vec.begin(), vec.begin() + numElemsThisTime );
This will be much faster than creating a new "vec" (whose size
is only equal to 'numElemsThisTime') each time you want to sort
something.
--
103 Jao-Chang Xsi,
Department of Fool Engineering
National TigerLand University,
Taipei, Taiwan.
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 140.112.48.60