看板 NTUGIEE_EDA 關於我們 聯絡資訊
//從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