CUBRID Coding Conventions
Table of Contents
- 1. Introduction
- 1.1 Need for Coding Convention
- 1.2 Basic Rules
- 1.3 Elements of Coding Conventions
- 1.3.1 Commenting Rules
- 1.3.2 Naming Rules
- 1.3.3 Coding Rules
- 1.4 Terms of Coding Conventions
- 1.4.1 Syntax Terms
- 2. Naming Rules
- 2.1 Common Naming Rules
- 2.2 File Names
- 2.3 Function Names
- 2.4 Variable and Constant Names
- 2.5 Type Names
- 3. Coding Rules
- 3.1 Indentation
- 3.2 Others
- 4. Commenting Rules
- 4.1 Common Rules
- 4.2 How to Write Different Formats of Comments
- 4.3 How to Write Different Usage of Comments
- 5. Rules for Declarations and Definitions
- 5.1 Function Declaration and Writing
- 5.2 Variable Declarations
- 5.3 Common Type Declaration
- 5.4 Constant Declarations
- 6. Rules for Expressions and Statements
- 7. File Configuration and Information
- 7.1 Program Configuration
- 7.2 File Configuration
- 7.3 Header Files
- 7.4 Source Files
- 8. Compatibility
- 9. Security
- 9.1 Assertion
- 10. Other Rules
1. Introduction
This chapter describes the need for CUBRID coding conventions, and elements and terms of coding conventions.
1.1 Need for Coding Convention
A large amount of maintenance cost is required throughout the software lifecycle. In addition, it is unlikely that the original developer of source code continues to maintain it for the whole lifecycle. Therefore, writing the source code in a way a person other than the original developer can understand it quickly and accurately is essential in reducing source code maintenance cost and increasing job efficiency.
With its high readability, source code written according to coding conventions helps developers to understand it quickly and accurately. This also makes easier to share them among project members and possible to produce a consistent source code appearance.
1.2 Basic Rules
Basically, CUBRID adopts “GNU Coding Standards” and “C Style and Coding Standards for SunOS” as its coding guide. It only uses basic features of the C/C++ language (compiler); it is not recommended to use techniques that are not used commonly.
GNU Coding Standards
http://www.gnu.org/prep/standards/standards.pdf
SunOS Coding Standards
http://opensolaris.org/os/community/on/cstyle.ms.pdf
This document describes a part to emphasize or additionally defined rules in the above guide.
1.3 Elements of Coding Conventions
1.3.1 Commenting Rules
Implementation Comment
Implementation comments describe implementation details or additional explanations, not source code specifications.
Documentation Comment
Documentation comments describe source code specifications. Developers can understand source codes through documentation comments.
1.3.2 Naming Rules
Naming rules are used to write names of functions and variables. These names should be descriptive enough to easily tell developers the source code structure.
1.3.3 Coding Rules
Indentation
Indentation is used to improve the readability of statements; programmers indent a certain amount of spaces from the first column on the left to the column on the right. It shows inclusion relationships between statements and blocks so that developers can easily understand the source code structure
Brace
Braces are used to indicate declarations and blocks. They show inclusion relationships between declarations, blocks and body.
White Space
White spaces are used to improve the readability of the source code. Using unnecessary braces or not using them where they are needed decreases the readability.
1.4 Terms of Coding Conventions
1.4.1 Syntax Terms
Variables
A variable is a space in memory where the state of an object or data is stored. It is defined by ANSI as follows:
“A character or a set of characters that represents a value for writing a program. It corresponds to an address in computer programming.”
Operators
An operator is a special symbol which is used to execute operations.
Expressions
An expression is an arithmetic or logical expression that returns a single value by using variables, operators and function calls.
Statements
A statement is a unit of execution, which is represented as an expression or a control flow statement.
Blocks
A block is an area between a pair of braces. Usually a block contains one or more statements, but it may not contain any in some cases.
Control Flow Statements
A control flow statement is a statement that controls the program flow.
Declarations
A declaration is used to define names and types of variables/functions, and return values, arguments and bodies of functions.
2.Naming Rules
This chapter describes naming rules.
2.1 Common Naming Rules
A. Using lowercase characters
There are some exceptions, but use lowercase characters for naming.
B. Avoiding the use of single-character names
Single-character names are unable to represent their meaning clearly, thus increase the possibility of errors because it is difficult to remember them. However, single-character names can be used as variable names in iterative statements; it is not recommended to use them if you can define a specific meaning.
C. Using underscores ("_")
Use underscores (“_”) to separate words.
D. Choosing words
The choice of words should be consistent as much as possible. For similar words such as add/insert, store/save/put, remove/delete, for example, use one of them consistently.
E. Avoiding use of abbreviations
For file, function, variable and constant names, use full names, not abbreviations. For example, use print_value or initialize_parameters instead of prt_val or init_params. However, commonly-known abbreviations and the ones frequently used as local variable names are allowed.
[Table 2-1] Example of Using Abbreviations
|
Item |
Example |
|
Bad example |
prt_val, init_params |
|
Good example |
print_value, initialize_parameters |
[Table 2-2] Example of Available Abbreviations
|
Available Abbreviations |
|
min, max |
F. Avoiding the use of negative Boolean names
Negative Boolean names represent double negative, making difficult to be understood. Therefore, use positive Boolean names.
[Table 2-3] Example of Using Boolean Names
|
Item |
Example |
|
Bad example |
is_not_available |
|
Good example |
is_available |
G. Observing simplicity and clarity
Use simple and clear names for files, functions, variables and constants so that they can represent their roles and purposes. It is recommended to use nouns with adjectives.
H. Observing English Word Order
Observe English word order when you create a name by combining multiple words. The following word order is recommended.
- Verb + Object.
- Subject + Verb + Object
- Subject + Verb
- djective + Noun
More accurate conventions are described in the detailed naming rules for functions and variables.
[Table 2-4] Example of English Word Order
|
Item |
Example |
|
Bad example |
date_check |
|
Good example |
check_date |
2.2 File Names
A. Using descriptive file names
Use descriptive file names that note the contents of the file.
B. Avoiding the use of duplicate file names
Do not use duplicate file names in the same project.
C. Avoiding the use of special characters
Do not use special characters other than underscores ("_").
D. Using lowercase alphabets
Use lowercase alphabets to create file names; use underscores ("_") between words.
E. Using prefixes
Use sub-system names as prefixes to create file names systematically. However, a prefix is not used for the name of a file which constitutes a common module.
[Table 2-5] Example of File Names
|
Item |
Example |
|
Example of using a prefix |
connection_list_sr.c |
|
Example of a common module |
tcp.c |
F. Using unique names
Do not use name that are likely to be duplicated; use unique names.
[Table 2-6] Example of Unique Names
|
Item |
Example |
|
Bad example |
evaluator.c |
|
Good example |
query_evaluator.c |
G. File Extension Rules
Comply with the rules described in Chapter 2 of SunOS Guide.
[Table 2-7] File Extension Rules
|
File |
Extension |
|
C source file |
.c |
|
Assembly source file |
.s |
|
Object file |
.o |
|
Header file |
.h |
|
Archive library file |
.a |
|
C shell source file |
.csh |
|
Bourne shell source file |
.sh |
|
ANTLR grammar file |
.g |
|
Yacc source file |
.y |
|
Lex source file |
.l |
2.3 Function Names
Use prefix_verb_noun(_suffix) format for a function name. For a prefix, use an abbreviation that represents a corresponding module.
For a function name, use a verb to say what a function does. Start a function name with the "get_" prefix if the function is a get that reads data. Start a function name with the "set_" prefix if the function is a set that sets data. Use a verb such as "is_" or "has_" for a function that returns a Boolean type.
[Table 2-7] Example of Function Names
|
Item |
Example |
|
Example |
qdump_print_xasl_type |
2.4 Variable and Constant Names
Names of variables and constants have prefix_noun(_suffix) format; adjective or adverb can be used. A compound noun such as noun+noun+noun format can be also used. For a prefix, a module name is used.
A. Global Variable Names
Use an uppercase character only for the first one after a prefix. For example, prm_Parameter_definition. This also applies to static global variables.
B. Local Variable Names
Do not use a prefix and use a simple name. More abbreviations are allowed for local variable names. However, if there are more appropriate ones than a, b, c or i, j, k, use them. For example, use a self-explanatory name that delivers meaning such as first_param. For a pointer variable, use "_p" as a suffix.
C. Constant Names
Use uppercase characters such as PRM_QUERY_CACHE_OPTION for a constant name.
D. Macro Names
As a constant-like global variable, use uppercase characters for a macro name that is defined with #define. However, when defining a constant, it is recommended to use a variable that include "const" rather than using a macro definition.
2.5 Type Names
A. Type, Struct and Enum Names
Use only lowercase characters for type, struct and enum names; only uppercase characters for typedef names. Do not use a suffix such as _t for a type name.
[Table 2-8]Example of Type, Struct, Enum and Typedef Names
|
Item |
Example |
|
typedef |
typedef SCAN_CODE |
|
struct |
struct log_2pc_coordinator |
|
enum |
enum log_flush |
B. Struct Member Name
Use only lowercase characters; do not use a prefix.
C. Function Parameter Names
Create a function parameter name in the same way as described in Local Variables.
This chapter describes coding rules..
3.Coding Rules
3.1 Indentation
A. Observing tab spacing
Use GNU indent without an option. Note that the indent program does not perfectly process #if/#else/#endif of cpp.
- For indent tool manuals, see the following web site: http://www.gnu.org/software/indent/manual
static bool qdump_print_db_value_array (DB_VALUE ** array_p, int count)
{
int i;
if (array_p == NULL)
{
return true;
}
for (i = 0; i < count; i++, array_p++)
{
if (!qdump_print_db_value (*array_p))
{
return false;
}
fprintf (foutput, "; ");
}
return true;
}
B. Observing indentation of enum definition
When you define an enumeration type value, write each item on a new line with indentatio.
typedef enum
{
LC_OBJECT = 0, /* Don't know if it is an instance or a class */
LC_CLASS, /* A class */
LC_INSTANCE /* An instance */
} LC_OBJTYPE;
C. Observing indentation of function parameters
When you define a function, if it cannot be defined in a single line because there are too many input parameters, move the last parameter in the line to the next line. Set the indentation of parameters in the next line to the column where the first parameter begins.
static void rop_to_range (RANGE * range, ROP_TYPE left, ROP_TYPE right); static void range_to_rop (ROP_TYPE * left, ROP_TYPE * rightk, RANGE range); static ROP_TYPE compare_val_op (DB_VALUE * val1, ROP_TYPE op1, DB_VALUE * val2, ROP_TYPE op2);
D. Observing indentation of function use parameters
When you define a function, if it cannot be defined in a single line because there are too many input parameters, move the last parameter in the line to the next line. Set the indentation of parameters in the next line to the column where the first parameter begins.
/* check if the two key ranges are mergable */
if (compare_val_op (&curp->key2, cur_op2,
&nextp->key1, next_op1) == ROP_LT ||
compare_val_op (&curp->key1, cur_op1,
&nextp->key2, next_op2) == ROP_GT)
{
/* they are disjoint */
nextp++;
next_n++;
continue;
}
E. Observing indentation of logical expressions
If a condition statement consisting of multiple logical operators, and they cannot be written in a single line, break up the logical expression into multiple lines. Place one logical operator per line, or combine multiple operators based on logical operation order.
If the line break is based on logical operators, indent a line by a tab from the column where the first logical expression started, beginning from the second line.
if ((s_id->direction == S_FORWARD && s_id->position == S_BEFORE)
|| (!BTREE_END_OF_SCAN (&s_id->s.isid.bt_scan)
|| s_id->s.isid.indx_info->range_type == R_KEYLIST
|| s_id->s.isid.indx_info->range_type == R_RANGELIST))
3.2 Others
A. Adding blanks
Place a space between words, before and after an operator, and after punctuation marks (e.g. comma, colon, etc.). However, spacing may not be required when unary operators are used. In addition, the last line should not be blank.
B. Using spaces for blanks
Except for a tab that is created by indentation, use a space for a blank instead of a tab.
C. Priority
When you write an expression, use parentheses to clearly specify the order of operations if multiple operators are used.
a = k * ((b + c) / d);
D. Number of columns
Write source code within 80 columns. If a comment is long, arrange it appropriately (see the Comments section).
E. Blocks
A brace and a control statement must be written on separate lines.
switch (last_scan_p->position)
{
case S_BEFORE:
status = qfile_scan_list_next (thread_p, next_scan_p, next_tuple_p, PEEK);
break;
case S_ON:
do
{
status = qfile_scan_list_next (thread_p, next_scan_p, next_tuple_p, PEEK);
if (status != S_SUCCESS)
{
break;
}
error_code = qfile_compare_tuple_helper (last_tuple_p->tpl,
next_tuple_p->tpl,
types, &cmp);
}
while (error_code == NO_ERROR && cmp == 0);
break;
case S_AFTER:
default:
status = S_END;
break;
}
4. Commenting Rules
This chapter describes commenting rules.
4.1 Common Rules
Comments are used to improve understanding of source code by providing brief explanation or describing additional information that cannot be delivered just with the code.
A. Basic rules
- All comments must be written in English.
- Simple comments: Complicated comments are difficult to read and to modify, increasing the possibility that improper comments are left as they are. Therefore, write simple comments only with necessary contents.
B. Source code that does not need comments
?Comments are not needed if you can clearly understand only by reading source code.
?Do not write comments about packaging or build. (e.g. directory information to be located)
?Do not write comments about source code developers or revision history. To provide this information, use a logging feature of the configuration management system.
There are three formats of comments: block comments, single-line comments and trailing comments. In terms of usage, there are file comments, function comments, variable comments, etc.
4.2 How to Write Different Formats of Comments
A. Block Comments
This format is used when comments are written in multiple lines. There are two types as shown below.
/* * This comment lines are too long to write within one line. * So, you can choose proper style like this. It is up to you. * GNU indent will not violate this style of comment. */
/* Nonzero means truncate lines in the display; zero means continue them. */
This format with * in every line is used to write comments at the top of the code, such as file comments and function comments.
For comments within the code, start with /*, do not use * when a line changes and end with */ according to the GNU definition. In addition, use the same indentation as the code.
B. Single-line comments
For a single-line comment, write comments in the following format.
/* codes to be used in the module */
C. Trailing Comments
This format is used to add a short comment beside the code.
int trail_file_vdes = 0; /* the trail log file descriptor */
4.3 How to Write Different Usage of Comments
Write comments at the top of the code for declaration and definition (e.g. function, variable and type); write comments at the end of the code for struct members or local variables. Make sure that comments at the end of the code do not go over the next line.
A. File comments
File comments are written in the following format. The copyright statement is followed by the GPL license statement.
/* * Copyright (C) 2008 Search Solution Corporation. All rights reserved by Search Solution. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ /* * list_file.c - Query List File Manager */ #ident "$Id$"
B. Function comments
Function comments are written in the block comment format. The first line describes brief information about a function, and the second line describes a value that the function returns. The third line and the rest lines describe the parameters of the function. Specify in, out, or on/out for each parameter. After the parameter description, add brief information that can help improve understanding of the function.
/*
* qfile_copy_list_id - Copy contents of source list_id into destionation list_id
* return: NO_ERROR or ER_FAILED
* dest_list_id(out): destination list_id
* src_list_id(in): source list_id
* include_sort_list(in):
*/
int
qfile_copy_list_id (QFILE_LIST_ID * dest_list_id_p,
const QFILE_LIST_ID * src_list_id_p,
bool is_include_sort_list)
C. Variable comments
Comments are written for static variable declaration in the following format (see the GNU coding guide).
/* Nonsero means truncate lines in the display; zero means continue them. */ int truncate_lines;
D. Type/struct comments
Comments with the format /* … */ are also used for struct, enum and typedef. In addition, write comments for a condition after #else and #endif (see the GNU Standard).
#ifdef foo … #else /* not foo */ … #endif /* not foo */ #ifdef foo #endif /* foo */ #ifndef foo … #else /* foo */ .. #endif /* foo */ #ifndef foo … #endif /* foo */
5. Rules for Declarations and Definitions
This chapter describes functions/variable declarations, common type definitions, initialization and using macros.
5.1 Function Declaration and Writing
For the naming rules of functions and parameters, see Chapter 2. Naming Rules; for the commenting rules, see Chapter 4. Commenting Rules.
- Function naming rules: 2.3 Function Names
- Function parameter naming rules: 2.5 C Function parameters
- Function commenting rules: 4.3 B Function comments
A. Observing simplicity and clarity
Write simple and clear functions. Long functions decrease readability and make maintenance difficult. It is recommended that the length of a function do not exceed 200 lines.
B. Observing the one-task-per-function rule
Implement a function so that it performs only one task. A function performing multiple tasks is difficult to understand because it decreases simplicity and clarity. Non-intuitive functions are likely to generate errors. Therefore, implement a function that performs a single task.
C. Function declaration rules
Do not use old declarations such as INTERFACE, PUBLIC, or PRIVATE; instead, only static and extern should be used. In addition, function declarations must be included in a header file (.h) and source file (.c). Even for a static function, function declaration must be included at the beginning of a source file. Use an appropriate header file in a source file instead of declaring an external function with extern rather than #include.
D. Validating input parameters
Write code that checks the validity of input parameters passed into the function.
E. Parameter declaration rules
Basically, declare function parameters in the order of out, in/out, and in. However, parameters that are frequently used throughout a module and passed like the keyword "this" of C++ (e.g. PT_PARSER parser, etc.) must be located at the beginning. For input parameters, use the const specifier. And use a pointer every place where const is required, such as const char * const in_p.
F. Function return value rules
Basically, create a function that can return an error code. If it is more significant to return a pointer value as void *malloc() or char *strcpy(), create a function that accepts an error code as an output parameter. That is, every function must return an error code in general. Only when a function is clear, it can return 0 or NULL. For example, int (*compar)(const void *, const void *) in qsort() returns a specific value instead of an error code.
Error codes are negative numbers, but NO_ERROR is 0 exceptionally. Basically, an error code means ER_XXXX_XXXX (a global error code) defined in dber.h. If it is necessary to define its own code in a module or function due to a program structure, define the code by using enum in a header file. In this case, use a negative number for an error. If it is not an error, use 0. That is, make the following statement become TRUE in most cases.
if (xx_function() < 0) if (xx_function() != NO_ERROR)
Although an error code is defined as DB_ERROR type, typedef is not used to define it in the code. (NO_ERROR is defined as 0.) Therefore, most functions have int as a return type. If the result of a function is positive number, it is a result of the function. If it is a negative number, it is one of error codes defined in DB_ERROR. If there is a function whose return type is DB_BOOL in the code, change its return type to int and make it return an appropriate error code.
When a function is called, perform an error checking for the result value. Even when the called function always return the same value, you must check the result value if the function is designed to return an error code according to its definition. In addition, checking result values must be performed after calling system functions. Especially, an error checking must be performed for malloc(). And make sure that exceptions are handled appropriately.
5.2 Variable Declarations
For the naming rules of variables, see Chapter 2. Naming Rules; for the commenting rules, see Chapter 4. Commenting Rules.
- Variable naming rules: 2.4 Variable and Constant Names
- Variable commenting rules: 4.3 C Variable comments
5.3 Common Type Declaration
If you want to use typedef for struct/enum, declare typedef first. If names are not specified in struct/enum, process them at once as follows:
typedef enum
{
FALSE = 0,
TRUE = 0
} bool;
5.4 Constant Declarations
Place a constant defined by #define within a block by using parentheses if the constant contains an expression. By doing so, you can prevent operation priority issues. However, #define is replaced during compilation and the name is not displayed in the symbol table, making debugging difficult. Therefore, use enum and const instead of #define when you declare a constant. The first element of enum must be set to 0.
#define MAX_SPEED 256
typedef enum
{
LC_OBJECT = 0, /* Don't know if it is an instance or a class */
LC_CLASS, /* A class */
LC_INSTANCE /* An instance */
} LC_OBJTYPE;
6. Rules for Expressions and Statements
This chapter describes rules for writing expressions and statements.
These rules correspond to the SunOS Guide (see Chapter 9, Chapter 15, and Chapter 17).
- Chapter 9: Statements
- Chapter 15: Goto
- Chapter 17: Multiple Assignments
This chapter describes how to write file configuration and information.
7. File Configuration and Information
7.1 Program Configuration
These rules correspond to the SunOS Guide.
- Chapter 3 Program Organization
7.2 File Configuration
These rules correspond to the SunOS Guide.
- Chapter 4: File Organization
7.3 Header Files
The structure of the header file (.h) is described below.
1. Copyright statement
2. Comments that describe the file contents, if necessary
3. Include checking with #ifndef
4. #ident line
5. #include other header files (system header first)
6. Repeat the followings in meaningful units
- #define, etc.
- typedef definition
- strcut, enum definition
- extern global variable declaration
- extern function declaration
/*
* Copyright (C) 2008 Search Solution Corporation.
* All rights reserved by Search Solution.
*
* This program is free software;
* you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street,Fifth Floor,Boston,MA 02110-1301 USA
*
*/
/*
* hdr.h - Brief description of this file as one sentence
*
* Note: if you feel the need
*/
#ifndef _HDR_H_
#define _HDR_H_
#ident "$Id$"
/* Explain main concept or logic of your code
contained in this file if possible */
#include "other.h"
#define DEFINE define
typedef strcut record RECORD;
/* codes to be used in the module */
enum code { CODE1, CODE2, CODE3 };
/* … */
struct record {
int no;
size_t size;
};
/* … */
extern int hdr_Global_variable;
/* … */
extern int hdr_process_line(char *line, int line_no);
extern int hrd_end_of_processing(const char *line);
#endif _HDR_H_
7.4 Source Files
The structure of the source file (.c) is described below.
1. Copyright statement
2. #ident line
3. Comments that describes the file contents, if necessary
4. #include header file (system header first)
5. You can write the followings in meaning units.
- #define, etc.
- typedef definition
- strcut, enum definition
- static variables definition
- static function declaration
- function definition (execution code)
Here, it is not recommended to place struct far way from a related typedef; declarations must be grouped in the same place. In addition, if there is #define that is only used for a specific function, it can be used at the beginning of the function or within the function.
The following formats used in the old file structure should not be used.
/***** IMPORTED DECLARATIONS*****/ /***** PUBLIC DEFINES *****/ /***** PUBLIC TYPEDEFS*****/ /****** PRIVATE DECLARATIONS *****/
8.Compatibility
This chapter describes how to implement compatibility.
A. Using compatibility related types
Do not use int instead of size_t or off_t that is available in the C library. If necessary, use int32_t or uint32_t. The recommended basic types are defined in the config.h. The types defined in dbport.h (e.g. DB_INT32 or DB_BOOL) must be used mostly for API.
B. Others
The additional information regarding compatibility corresponds to the SunOS Guide.
- Chapter 20: Portability
9. Security
This chapter describes how to implement security code.
9.1 Assertion
Use assert() appropriately in the code after #include assert.h. Do not use it frequently and try to avoid calling other functions in the assert expression. The most recommended types are as follows:
- Checking whether a parameter of a function is valid
- Warning risks in advance
- Verifying a return value at the end of a function as a unit test
10. Other Rules
This chapter describes other rules to comply with.
- Delete the extern "C" part.
- Do not use inline or register.
- Use volatile only for very sensitive parts.
- After coding, use the GNU indent to align the indentation.
- There must be no warning by compiling with the following option in the gcc:
-all -extra -missing-prototypes -redundant-decls -long-long - Check the code by using splint if the compiling is successful.
