标签:
|
The C Language Style for Scalability (CLASS) defines a consistent style and organization for scalable C library and application code built on modern C compilers and operating systems. CLASS aims to collect industry best practice into one reusable standard.
Copyright (c) 2009-2013 iMatix Corporation
This Specification 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 3 of the License, or (at your option) any later version.
This Specification 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, see <http://www.gnu.org/licenses>.
This Specification is a free and open standard[2] and is governed by the Digital Standards Organization‘s Consensus-Oriented Specification System (COSS)[3].
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119[1].
CLASS aims to be a complete and reusable style and organization guide for scalable C projects. CLASS collects best practice to solve a set of specific and well-known quality problems with C projects. It evolved from the style guide of the ZeroMQ CZMQ project. CLASS is plug compatible with the "coding style guide" requirements of the C4 process[4].
The specific goals for this Specification are to:
The goal of CLASS is to help programmers write high-quality C code in a consistent fashion. We define "high quality" primarily thus:
Our main tool for achieving this is to identify and apply the best patterns and styles. Tthe reader can learn these once, and then see them repeatedly across a wide body of code. Deviations from familiar patterns can then be taken as a sign of low-quality code that is more likely to contain errors and less remixable.
With this Specification we aim to address a specific set of problems that hurt the quality, remixability, and economics of many C projects:
While these problems can affect all software projects, we solve them specifically for C projects.
The overall unit of work is a project that builds as a library with a set of executable test programs and supplemental command-line tools.
The project is composed of classes, where each class covers one area of work and is implemented as a source file with matching header file.
Each class implements a series of methods, where each method performs one task and is implemented as a C function.
The language for all names and comments SHALL be English.
Names SHOULD be chosen for ease of readability, and consistency. Unless otherwise specified, the following style rules apply to all given names:
The project SHALL focus on one identifiable problem space, which SHALL be stated explicitly in the project README.
The project SHALL have these short names and abbreviations:
These names SHALL be noted in the project README.
The project SHALL contain at least these files and directories:
The project MAY contain these files and directories which MUST have these names if present at all:
The project SHOULD install these files:
The project SHALL NOT use deeper nested subdirectories.
The project SHALL depend at least on CZMQ (libczmq), which imports ZeroMQ (libzmq), to provide portable APIs around networking, threads, file systems, and other aspects.
The project SHALL provide two services via header files:
These two services MAY be combined into one project header file ((myproj.h), or MAY be split into an external header file (myproj.h) and an internal header file (myproj_internal.h). The project MAY further break down these header files if necessary.
The external header file SHALL define a version number for the project as follows:
// MYPROJ version macros for compile-time API detection
#define MYPROJ_VERSION_MAJOR 1
#define MYPROJ_VERSION_MINOR 0
#define MYPROJ_VERSION_PATCH 0
#define MYPROJ_MAKE_VERSION(major, minor, patch) ((major) * 10000 + (minor) * 100 + (patch))
#define MYPROJ_VERSION MYPROJ_MAKE_VERSION(MYPROJ_VERSION_MAJOR, MYPROJ_VERSION_MINOR, MYPROJ_VERSION_PATCH)
The project header file SHALL assert the required version numbers for any dependencies immediately after including their respective header files, like this:
#include <czmq.h>
#if CZMQ_VERSION < 10203
# error "myproject needs CZMQ/1.2.3 or later"
#endif
Definitions in the external header file are visible to calling applications as well as class source code. The external header file SHALL include all class header files that form part of the public API for the project.
Definitions in the internal header file are visible only to class source code. The internal header file, if present, SHALL include the external header file, all class header files, and all system and library header files needed by the project. The primary goal here is to keep delicate system-dependent #includechains in a single place, and away from class source code.
# Project Title
<One-paragraph statement of the goals of the project, and the problems it aims to solve>
## References
* Contribution policy is defined by C4 (http://rfc.zeromq.org/spec:21).
* Project style guide is defined by CLASS (http://rfc.zeromq.org/spec:14).
* short name: <shortname>
* abbreviation: <abbreviation>
* prefix: <prefix>
* Licensed under <license name>, see COPYING
* Language level: C99
The project SHOULD use the C99 language for best clarity, but MAY use the C89 language for compatibility with older platforms. The language level SHALL be noted in the project README and all source code SHALL conform to it.
NOTE: Microsoft Visual C/C++ does not support C99 and projects must build using C++ language extensions to get access to C99 syntax. Because of this, projects SHOULD NOT use any C99 syntax that is not a strict subset of C++.
Project source code SHALL NOT include any header files except the project header file. This ensures that all class source code compiles in exactly the same environment.
Project source code SHALL NOT define "magic numbers" (numeric constants); these SHALL be defined in the external or internal header file, as appropriate.
Projects MAY use the preprocessor for these purposes:
Projects SHOULD NOT use the preprocessor for other work except when it significantly reduces the complexity of code.
Macro names SHALL be uppercase when they represent constants, and lowercase when they act as functions.
Each class SHALL be written as two files:
These two files SHALL be the original documentation for the class. Specifically, the class header SHALL define the API for the class, and the class source file SHALL define the implementation of each method.
Class names SHALL follow the General Style for Naming. We will use mymod in examples.
Every source and header file SHALL start with an appropriate file header that states at least:
Here is a template file header for an LGPL open source project:
/* =========================================================================
<name> - <description>
-------------------------------------------------------------------------
Copyright (c) <year> - <company name> - <website>
Copyright other contributors as noted in the AUTHORS file.
This file is part of <project name>, <description>
<website>
This is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the
Free Software Foundation; either version 3 of the License, or (at your
option) any later version.
This software is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANT-
ABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this program. If not see http://www.gnu.org/licenses.
=========================================================================
*/
We define two types of class:
A class may be stateful or stateless but SHALL NOT mix the two approaches.
A stateful class SHALL provide these methods:
A stateful class MAY provide these methods, and SHALL use these names when providing such functionality:
A stateless class SHALL provide this method:
Method names SHALL follow the General Style for Naming. Method names SHOULD be verbs ("destroy", "insert", "lookup") or adjectives ("ready", "empty", "new"). The method name SHOULD imply the method return type, where verbs return a success/failure indicator, if anything, and adjectives return a value or instance.
The class header file SHALL have this layout:
Here is a template header file for stateful classes, not showing the file header:
#ifndef __MYMOD_H_INCLUDED__
#define __MYMOD_H_INCLUDED__
#ifdef __cplusplus
extern "C" {
#endif
// Opaque class structure
typedef struct _myp_mymod_t myp_mymod_t;
// Create a new <class name> instance
CZMQ_EXPORT myp_mymod_t *
myp_mymod_new (void);
// Destroy a <class name> instance
CZMQ_EXPORT void
myp_mymod_destroy (myp_mymod_t **self_p);
// Self test of this class
void
myp_mymod_test (bool verbose);
#ifdef __cplusplus
}
#endif
#endif
Here is a similar template header file for stateless classes:
#ifndef __MYMOD_H_INCLUDED__
#define __MYMOD_H_INCLUDED__
#ifdef __cplusplus
extern "C" {
#endif
// Self test of this class
int
myp_mymod_test (bool verbose);
#ifdef __cplusplus
}
#endif
#endif
All public methods SHALL be declared with CZMQ_EXPORT in the class header file so that these methods are properly exported on operating systems that require it.
The class source file SHALL define:
For stateful classes, the class structure has one or more properties defined as a private C structure in the class source file.
This SHOULD be defined as follows:
// Structure of our class
struct _mymod_t {
<type> <name>; // <description>
};
Property names SHALL follow the General Style for Naming. Property names SHOULD be nouns or adjectives (typically used for Boolean properties). We will use myprop in examples.
Argument names SHALL be consistent with property names.
In stateless classes, the only standard method is myp_mymod_test (), which SHALL conduct a self test of the class, returning silently on success, and asserting on failure.
The self test method shall take this general form:
// --------------------------------------------------------------------------
// Runs selftest of class
void
myp_mymod_test (int verbose)
{
printf (" * myp_mymod: ");
// Conduct tests of every method
printf ("OK\n");
}
The constructor SHALL take this general form:
// Create a new myp_mymod instance
myp_mymod_t *
myp_mymod_new (<arguments>)
{
myp_mymod_t *self = (myp_mymod_t *) zmalloc (sizeof (myp_mymod_t));
if (self) {
self->someprop = someprop_new ();
if (self->someprop)
self->anotherprop = anotherprop_new ();
if (self->anotherprop)
self->lastprop = lastprop_new ();
else
myp_mymod_destroy (&self);
}
return self;
}
The destructor SHALL take this general form:
// Destroy a myp_mymod instance
void
myp_mymod_destroy (myp_mymod_t **self_p)
{
assert (self_p);
if (*self_p) {
myp_mymod_t *self = *self_p;
someprop_destroy (&self->someprop);
anotherprop_destroy (&self->anotherprop);
lastprop_destroy (&self->lastprop);
free (self);
*self_p = NULL;
}
}
The class MAY offer a duplicator method which creates a full copy of an instance; if it offers such semantics, the method MUST be calledmyp_mymod_dup () and take this general form:
// Create a copy of a myp_mymod instance
myp_mymod_t *
myp_mymod_dup (myp_mymod_t *self)
{
if (self) {
assert (self);
myp_mymod_t *copy = myp_mymod_new (...);
if (copy) {
// Initialize copy
}
return copy;
}
else
return NULL;
}
A class MAY act as a list container for other items, which may be child class instances, strings, memory blocks, or other structures.
Such a container class SHALL keep the list cursor position in the instance, and provide the following methods for navigating the list:
// Return first item in the list or null if the list is empty
item_t *
myp_mymod_first (myp_mymod_t *self)
{
assert (self);
// Reset cursor to first item in list
return item;
}
// Return next item in the list or null if there are no more items
item_t *
myp_mymod_next (myp_mymod_t *self)
{
assert (self);
// Move cursor to next item in list
return item;
}
The class MAY expose instance properties via its API, in which case this SHALL be done through accessor methods.
To return the value of a property the class SHALL define an accessor method like this:
// Return the value of myprop
<type>
myp_mymod_myprop (myp_mymod_t *self)
{
assert (self);
return self->myprop;
}
To write the value of a property, if this is permitted, the class SHALL define an accessor method like this:
// Set the value of myprop
void
myp_mymod_set_myprop (myp_mymod_t *self, <type> myprop)
{
assert (self);
self->myprop = myprop;
}
When a method (such as an accessor method) accepts a string argument as primary argument, it SHOULD use a variable argument list and perform vsnprintf formatting on that string argument.
The class MAY offer any number of other methods that operate on the instance. These methods shall take this general form:
A method may take ownership of an object instance and then act as a destructor of the object instance at some later stage. In that case the method SHALL use the same style as the destructor.
Methods SHOULD use one of the following patterns for returning values to the caller:
One of the goals of CLASS is to hide heap use as far as possible within classes. Application programs SHOULD use the heap only through constructors and duplicators (including the library strdup () function). Class methods MAY use the heap with care, but follow these rules:
Classes SHOULD NOT use static variables except in exceptional cases, such as for global variables.
Static variables are not thread safe and they are therefore considered poor practice.
Particularly for representing any temporary state inside a class body, stack variables SHALL be used in place of static variables.
Functions that are not exported by a class are defined as static and named s_functionname () with no use of the project abbreviation or class name.
Static functions MAY be defined before first use, or MAY be prototyped and defined immediately after first use.
Static functions SHOULD NOT be collected at the end of the class source code.
Indentation SHALL be 4 spaces per level. Tab characters SHALL NOT be used in code.
Functions SHALL be prototyped as follows:
<type>
<name> (<arguments>);
Functions SHALL be defined as follows:
<type>
<name> (<arguments>)
{
<body>
}
When the project uses C99, stack variables SHALL be defined in-line, as close as possible to their first use, and initialized. For example:
myp_mymod_t *mymod = myp_mymod_new ();
char *comma = strchr (surname, ‘.‘);
When the project uses C89, stack variables SHALL all be defined and initialized at the start of the function or method where they are used.
Code lines of more than 80-100 characters SHOULD be folded for readability.
Single-statement blocks SHALL NOT be enclosed in brackets.
This is the form of a single-statement block:
if (comma == NULL)
comma = surname;
In else statements, the else SHALL be put on a line by itself.
Multiple if/else tests SHALL be stacked vertically to indicate that the order is arbitrary.
This is the form of a stacked if statement block:
if (command == CMD_HELLO)
puts ("hello");
else
if (command == CMD_GOODBYE)
puts ("goodbye");
else
if (command == CMD_ERROR)
puts ("error");
With multi-statement conditional blocks, the closing bracket SHALL be put on a line by itself, aligned with the opening keyword.
This is the form of a stacked if statement block with brackets around each conditional block:
if (command == CMD_HELLO) {
puts ("hello");
myp_peer_reply (peer, CMD_GOODBYE);
}
else
if (command == CMD_GOODBYE) {
puts ("goodbye");
myp_peer_reply (peer, CMD_DISCONNECT);
}
else
if (command == CMD_ERROR) {
puts ("error");
myp_peer_close (peer);
}
This is the form of a while statement:
char *comma = strchr (surname, ‘,‘);
while (comma) {
*comma = ‘ ‘;
comma = strchr (surname, ‘,‘);
}
Comments on code SHALL be used lightly and where necessary.
In C99 projects the syntax for comments is:
In C89 projects the syntax for all comments SHALL be the C /* … */ style.
This is the general template for a method comment header:
// --------------------------------------------------------------------------
// Finds the first item in the list, returns null if the list is empty.
myp_mymod_t *
myp_mymod_first (myp_mymod_t *self)
{
...
Blank lines SHALL be used to separate blocks of code to improve readability, in these cases:
Blank lines SHALL not be used in these cases:
Code SHALL NOT use extra spacing to create vertical alignment.
char *comma = strchr (surname, ‘,‘);
while (comma) {
*comma = ‘ ‘;
comma = strchr (surname, ‘,‘);
}
Punctuation SHALL follow English rules as far as possible.
This is the style for unary operators, with a space after but not before the operator:
char_nbr++;
This is the style for binary operators, with a space before and after the operator:
comma = comma + 1;
This is the style for the ?: operator:
comma = comma? comma + 1: strchr (name, ‘.‘);
This is the style for semi-colons, with a space after but not before:
for (char_nbr = 0; *char_nbr; char_nbr++)
char_nbr++;
This is the style for parentheses, with a space before the opening, and after the closing parenthesis, with multiple opening or closing parentheses joined together without spaces:
node = (node_t *) zmalloc (sizeof (node_t));
if (!node)
return -1;
This is the style for square brackets:
comma = name [char_nbr];
This is the style for pointer dereferences, with no space before or after the ‘->‘:
self->name = strdup (name);
Classes SHOULD check the validity of arguments using assertions. That is, misuse of the API is considered a programming error, not a run-time error.
The return statement MAY be used at any point in a function to return to the caller.
If the function needs to do clean-up (e.g., free a number of properties), the code MAY use goto and a single clean-up block at the end of the function. Such a clean-up block SHALL follow the last "normal" return.
A void function SHALL NOT end in an empty return statement.
for (array_index = 0; array_index < array_size; array_index++) {
// Access element [array_index]
}
<type>
All projects SHALL depend at least on ZeroMQ (libzmq) and CZMQ (libczmq), which provide portable APIs around networking, threads, file systems, and other aspects.
This example shows the general style of native code:
#if (defined (__UNIX__))
pid = GetCurrentProcessId ();
#elif (defined (__WINDOWS__))
pid = getpid ();
#else
pid = 0;
#endif
The following types and macros are defined by CZMQ and may be used safely in all code:
Compiler warnings SHOULD always be treated as fatal. The following is a list of constructs known to cause warnings on some but not all compilers:
Code generation MAY be used to produce classes mechanically when there is compelling benefit.
export PATH=../scripts:$PATH
gsl -q -script:<script>.gsl <model>.xml
The use of opaque data structures that are accessed via references is thread safe. However:
21/CLASS - C Language Style for Scalability——ZeroMQ官网建议的C语言命令规范
标签:
原文地址:http://www.cnblogs.com/jayzee/p/4403604.html