Skip to content

Instantly share code, notes, and snippets.

@district10
Last active August 29, 2015 14:26
Show Gist options
  • Save district10/51005e331515b9272986 to your computer and use it in GitHub Desktop.
Save district10/51005e331515b9272986 to your computer and use it in GitHub Desktop.
代码规范

CVRS C++ Coding Style 规范

tags: docs coding_style

read official version: http://cvrs.whu.edu.cn/docs/CVRS-CodingStyleGuide.html

read newest version:


notes on <Google C++ Style Guide

The #define Guard

#ifndef FOO_BAR_BAZ_H_
#define FOO_BAR_BAZ_H_

...

#endif  // FOO_BAR_BAZ_H_

Function Parameter Ordering

put all input-only parameters before any output parameters.

Names and Order of Includes

Don't use Unix's directory shortcuts.

For example, google-awesome-project/src/base/logging.h should be included as: #include "base/logging.h"

Order of Includes:

  • dir2/foo2.h.
  • C system files.
  • C++ system files.
  • Other libraries' .h files.
  • Your project's .h files.

Named Namespaces

using namespace foo;  // Forbidden -- This pollutes the namespace.

You may use a using-declaration anywhere in a .cc file, and in functions, methods or classes in .h files.

Nested Classes

Okay for using, but you should know & remember:

Nested classes can be forward-declared only within the definition of the enclosing class. Thus, any header file manipulating a Foo::Bar* pointer will have to include the full class declaration for Foo.

Local Variables

int j = g();  // Good -- declaration has initialization.
vector<int> v = {1, 2};  // Good -- v starts initialized.

Static and Global Variables

One way to alleviate the destructor problem is to terminate the program by calling quick_exit() instead of exit(). The difference is that quick_exit() does not invoke destructors and does not invoke any handlers that were registered by calling atexit(). If you have a handler that needs to run when a program terminates via quick_exit() (flushing logs, for example), you can register it using at_quick_exit(). (If you have a handler that needs to run at both exit() and quick_exit(), you need to register it in both places.)

The default constructor is called when we new a class object with no arguments.

CVRS C++ Coding Style 规范

tags: docs coding_style

read official version: http://cvrs.whu.edu.cn/docs/CVRS-CodingStyleGuide.html

read newest version:


零、绪论

  1. 注释分为两种,第一种是给自己看或者其他看代码的人看,用 // comment 或者 /* comment */, 第二种是会被放到文档中,用 //! comment 或者 /*! comment */(也就是多加一个 ! 的事)。
  2. 代码宽度不能超过 80 个字符。(注释也不能)
  3. 代码编辑完后,要把 trailing spaces 去掉(Notepad++ 中 Edit--Blank Operations--Trim Trailing Space

一、C++ 语言部分

1)文件:

C 语言中,单词全小写,单词之间用 _ 连接,e.g. feature_detector.h, feature_detector.c

C++ 中,单词首字母用大写表示,单词之间不空格,e.g. FeatureDetector.hFeatureDetector.cpp

2)类:

  1. 定义声明:对于类的作用和内容进行简单的说明,用 //! remarks
  2. 命名规则:e.g. ComputingTemperature。(不同于 MFC,如 MFC 中 CZoomDlg,在类前加 C。而小组统一直接表示为 ZoomDlg。)

3)结构体:

C++ 中结构体不需要 typedef 便可直接当成类型使用,也就是说,下面两种是一样的

// method 1
struct ElecStateStruct {
    char *elec_name;
    char *elec_state;
};
// method 2
typedef struct ElecStateStruct {
    char *elec_name;
    char *elec_state;
} ElecStateStruct;

但推荐使用第二种

命名规则和类的一样。

4)函数和变量:

函数:

  1. 定义声明:在头文件(.h 文件)的类中,一般先写 private 型,再写 public 型。并先定义变量后定义函数。内容写于 .cpp 文件,并对其说明。
  2. 命名规则:currentTemperature( ... )filtering( ... )
  3. 注释:与 C 一致,须在函数前进行说明。说明函数功能、参数含义及返回值等,e.g.
//! Function is used for feature point extraction,
//! giving ... type variables,
//! returns 1 means success, 0 means failure
int extractionPoint( ... )
{
    ...
}

变量:

  1. 定义声明:与 C 一致。
  2. 命名规则:全局(e.g. _currentTemperature),局部(e.g. currentTemperature),函数内部的变量可以尽可能短。
  3. Qt 中信号和槽也可用 C 语言风格。比如:
signals:
    void angle_resolution( double res );
    void angleResolution( double res );

public slots:
    void on_angle_resolution( double res );
    void onAngleResolution( double res );

5)宏:

全大写,不以 _ 开头(避免重定义覆盖标准库或其他地方的宏),e.g. CURRENT_TEMPERATURE

三、程序排版规则

原则 0:

  1. 美观(不要吝惜你的空格和空行)
  2. 自身的一致性
  3. 大家的一致性(规范)

原则 1:

  1. 用等宽字体
  2. 不使用 tab 键,用 4 个空格代替(因为不同 IDE、编辑器、网页,对 tab 的显示宽度不一致。)
  3. 缩进(indent)用 4 个空格(Visual Studio 需要设置)

C Example:

#include <stdio.h>                                         // <-- 注意这里 <stdio.h> 前的空格
#include <math.h>
                                                           // <-- 【#include】s 后空行
#define PI (3.1415)                                        // <-- 最好都加上括号

typedef struct PointCoordinate
{
    int x ;
    int y;
} Point;

//! setting coordinate                                     // <-- 函数说明
Point set_point( int a, int b );                           // <-- 函数声明,参数列表这里有空格
//! get the area of the circle
double get_area( int radius );

void main()
{
    // define the coordinate of the center, the radius and the area of a circle
    Point point_circle;                                    // <-- 变量定义规则:小写,之间加下划线
    int radius_circle;
    double area_circle;

    // input the information of a circle                   // <-- 函数部分步骤意义说明规则
    printf( "please input point.x & point.y: \n" );        // <-- 函数调用,参数列表这里有空格
    scanf( "%d%d", &point_circle.x, &point_circle.y );
    printf( "please input the radius of the circle:\t" );
    scanf( "%d", &radius_circle );

    area_circle = PI * radius_circle * radius_circle;
    printf( "the area of a circle is: %lf\n", area_circle );
}

Point setPoint( int a, int b )                             // <-- 函数定义,参数列表这里有空格
{
    Ponit pt;
    pt.x = a;
    pt.y = b;
    return pt;
}

double getArea( int radius )
{
    double S;
    S = PI * radius * radius;
    return S;
}

加空格只是出于易读性的考虑,所以我们用 scanf( "%d", &radius_circle ); 而不是 scanf("%d", &radius_circle);。但如果行过长,就可以省略这些空格,比如:

while ( 1 == scanf("%d", &num) ) {       // 这里没空格
    printf( "%d\n", num );               // 这里有空格
}

C++ Example:

#include <iostream>

#define PI (3.1415)
#define MAX (300)

//! basic class,2dim_point                                // <-- 对类的说明
class  Point
{
private:                                                   // <-- 先 private
    int x;                                                 // <-- 不能是 _x
    int y;
public:
    int getX( ) { return x; }                              // <-- 极其简单的函数,可以放在一行
    int getY( ) { return y; }
    
    //! setting coordinate                                 // <-- 函数说明(这个函数,就不该放在一行)
    void setPoint( int a, int b )
    {
        x = a;
        y = b;
    }
    
    //! calc distance from this point to another
    double distanceTo( Point &pt );                        // <-- 长的函数都放在 cpp 文件
};

//! derived class circle
class Circle : public Point
{
    private:
        //! radius of a circle                             // <-- 变量说明格式
        int radius;
    public:
        //! set the size of the radius
        int setRadious( int r ) { radius = r; }
        void getRadious( ) { return radius; }
        //! get the area of the circle
        double getArea( ) { return PI * radius * radius; }
};

void main( )
{
    // define a circle
    Circle circle1;

    // set up circle center & radius                       // <-- 对程序中的部分步骤说明
    circle1.setPoint(200, 250);
    circle1.setRadius(100);

    // output the X coordinate of the center of the circle1
    cout << "x = " << circle1.getX() << endl;
    // output the X coordinate of the center of the circle1
    cout << "the Area of Circle1 is " << circle1.getArea() << endl;
}

正确和错误举例

/*
 * 加足够的空格
**/

for(int i;i<count;i++)                                     // WRONG
for ( int i; i < count; i++ )                              // CORRECT
for ( int i; i < count; ++i )                              // EVEN BETTER

int max(int a,int b)                                       // WRONG
int max( int a, int b )                                    // CORRECT

max(23,45);                                                // WRONG
max(23, 45);                                               // WRONG
max( 23, 45 );                                             // CORRECT
max( 21, max(max(3,8), 34) );                              // CORRECT,体会一下这些空格的有无

show();                                                    // CORRECT
show( );                                                   // CORRECT

/*
 * 大括号的位置
**/

for ( int i; i < count; ++i )                              // CORRECT,注意这里的空格
{
    ...
}

for ( int i; i < count; ++i ) {                            // CORRECT
    ...
}

// 同理,正确的 while,if,do while 应为
while ( CONDITION ) {
    ...
}

while ( CONDITION )
{
    ...
}

if ( CONDITION ) {
    ...
}

if ( CONDITION )
{
    ...
}

if ( CONDITION_1 ) {
    ...
} else if ( CONDITION_2 ) {
    ...
} else {
    ...
}

do {
    ...
} while ( CONDITION );


/*
 * 永远都加 {},哪怕只有一行代码,适用于 if、for、while 和函数声明+定义
**/
if ( FATAL_ERROR )                                         // WRONG
    return EXIT_FAILURE;

if ( FATAL_ERROR ) {                                       // CORRECT
    return EXIT_FAILURE;
}

int getX( ) return x;                                      // WRONG
int getX( ) { return x; }                                  // CORRECT


/*
 * 函数声明和调用的参数规范
**/

void func();                                               // WRONG
void func2(int i, int j);

void func( );                                              // CORRECT
void func2( int i, int j );

其他一些说明

注释的放置

流程上的东西,夹在代码内,如:

// set up circle center
circle.setPoint( 200, 250 );
// set up circle radius
circle.setRadius( 100 );

补充说明性质的东西,放在行尾,如:

fprintf( fp,
         "| %*i "              // index
         "| %*s "              // timestamp
         "| %*s%d%*s "         // log level
         "| %*s%s%*s "         // type (aligned to center)
         "| %-*s "             // action
         "| %*s |\n",          // messag
         ... );

对齐

通常不需要对齐,比如:

int x0;
double dx;

不必写成:

int    x0;
double dx;

但如果很多东西,有一种莫名的联系,对齐则是上上之选,比如:

/*
 * 对齐实例 1
**/
ust.time              = parse8BytesToDouble(ba, c, f); c += 8;
// q target
ust.q_target[0]       = parse8BytesToDouble(ba, c, f); c += 8;
ust.q_target[1]       = parse8BytesToDouble(ba, c, f); c += 8;
ust.q_target[2]       = parse8BytesToDouble(ba, c, f); c += 8;
ust.q_target[3]       = parse8BytesToDouble(ba, c, f); c += 8;
ust.q_target[4]       = parse8BytesToDouble(ba, c, f); c += 8;
ust.q_target[5]       = parse8BytesToDouble(ba, c, f); c += 8;


/*
 * 对齐示例 2
**/
enum URFunctionCodes { /* 0-128d */
    // mb_req_pdu
    READ_COILS                   = 0x01,  // read output bits
    READ_DISCRETE_INPUTS         = 0x02,  // read input bits
    READ_HOLDING_REGISTERS       = 0x03,  // read output registers
    READ_INPUT_REGISTERS         = 0x04,  // read input registers
};


/*
 * 对齐示例 3
**/
mcuAddr.insert(  ROLL_PITCH_YAW,        0x000B  );
mcuAddr.insert(  accX_accY_accZ,        0x000E  );
mcuAddr.insert(  GyroscopeX,            0x0011  );

包括行末的 // 注释也最好对齐。 外,强烈建议 Qt 的信号和槽也对齐,不要使用

connect(mcu, SIGNAL(mcuTimestamp(quint32)), this, SLOT(onMCUTimestamp(quint32)));

而是使用:

connect( mcu, SIGNAL(mcuTimestamp(quint32)),
         this, SLOT(onMCUTimestamp(quint32)) );

参数列表也要对齐:

// method 1
return QString().sprintf( "%02d:%02d:%02d.%03d"         // e.g. 01:23:45.678
                        , dt.time().hour()
                        , dt.time().minute()
                        , dt.time().second()
                        , dt.time().msec() );
// method 2
return QString().sprintf( "%02d:%02d:%02d.%03d",        // e.g. 01:23:45.678
                          dt.time().hour(),
                          dt.time().minute(),
                          dt.time().second(),
                          dt.time().msec() );
// but not this one
return QString().sprintf( "%02d:%02d:%02d.%03d",        // e.g. 01:23:45.678
                          dt.time().hour(), dt.time().minute(),
                          dt.time().second(), t.time().msec() );
// and, of course, not this one
return QString().sprintf( "%02d:%02d:%02d.%03d", dt.time().hour(),
    dt.time().minute(), dt.time().second(), t.time().msec() );

Q:如何写文档? A:用 Markdown。

本文源码:https://gist.githubusercontent.com/district10/51005e331515b9272986/raw/CodingStyleOfChangshaTeam_CVRS.md

(要翻墙)

Editor Configuration

Visual Studio

安装:

  1. 安装 VisualLint.exe,Python2.exe(注意加到环境变量)
  2. 打开 VS,配置 cpplint.py

配置 Visual Studio

Tools--Options...--Text Editor--All Languages--Tabs,设置:

  1. tab size: 4
  2. indent size: 4
  3. insert spaces

如果要把已有的 tab 转化成 spaces,用: 先选中文本,再 Edit--Advanced--Untabify Selected Lines

Visual Lint 的使用

打开 VS 后会提示配置,选 uncheck 第一个,check 第三个(Google 那个),然后选择 cpplint.py 文件的目录,然后就可以了。

需要 lint 的时候点击那个“蜘蛛”按钮。

装一些 extensions:

CodeMaid:

  • Options
    • Cleaning
      • General, check Automatically run cleanup on file save

//

日志类 Logger

tags: docs logger manual

read online:


一、简介

Logger 是日志类,用于打印输出。

可运行 Demo/LoggerExample 示例看效果。

生成的 Log 文件为 log_1439253703271.txt(默认输出到 D 盘根目录,程序退出时会自动保存), 为 Markdown 表格形式的纯文本:

INDEX TIMESTAMP LEVEL TYPE ACTION REMARKS
1 2015/08/11 08:41:45:464 1 SP20000C construct
2 2015/08/11 08:41:47:293 1 SP20000C destruct
3 2015/08/11 08:41:48:435 1 LMS turn on READING
4 2015/08/11 08:41:49:195 1 LMS turn off READING
5 2015/08/11 08:41:56:100 1 UR destruct nice nice

二、使用

1. 添加连接依赖

logger.h 位于 Utils 模块,所以 CMakeLists.txt 中得添加

target_link_libraries( ${PROJECT_NAME}  Utils )

2. 添加头文件

#include "logger.h"

3. 使用

// 第一个参数为 log 的项(在 Logger 类中定义的方法后文再介绍)
Logger::log( BCD::LMS::CONNECT );

// 第二个参数为“补充说明内容”,可为空。支持 QString、std::string 和 char * 类型字符串
Logger::log( BCD::LMS::CONNECT, QString("<QString> remarks") );
Logger::log( BCD::LMS::CONNECT, std::string("<c++ string> remarks") );
Logger::log( BCD::LMS::CONNECT, "<c style string> remarks" );

// 使用起来就像 std::cout(注意:这些内容不会存到日志文件中,仅供打印输出)
Logger::log( ) << 3 << "is three.";
Logger::log( 8 ) << "emphasized log."; // 0..9

三、添加 Logger 项

1. 把 TYPE_DEMO_MODULE 改成自己的模块名称,格式为 TYPE_模块名

enum TypeID {
    TYPE_LMS,
    TYPE_IMU,
    TYPE_MCU,
    TYPE_UR,
    TYPE_ARM,
    TYPE_SP20000C,
    TYPE_C2,
    TYPE_DEMO_MODULE,  // <-- 修改这一行
};

logger.cpp 里面还要修改这一行:

types[  TYPE_DEMO_MODULE  ] = QObject::tr(  "DEMO MODULE"  );

2. 重载函数

在 Logger 类里把这三处修改一下即可,DEMO_MODULE 改成自己的 模块名

GENERIC_LOG_QSTRING(  DEMO_MODULE  )
GENERIC_LOG_CSTR(  DEMO_MODULE  )
GENERIC_LOG_STRING(  DEMO_MODULE  )

3. 添加 Log 项

这部分比较复杂,先在 logger.h 中修改这一部分,改 DEMO_MODULE 为自己的模块名

// DEMO_MODULE
namespace DEMO_MODULE {
enum Action {
    DEMO_MODULE                   = TYPE_DEMO_MODULE<<LOG_ENTRY_OFFSET,
    ...
};
}  // namespace DEMO_MODULE

logger.h 中的 log 项和 logger.cpp 中的 log 项对应起来,对应关系为:

// logger.h`
SOMETHING,
// logger.cpp
ACTION( DEMO_MODULE::SOMETHING,                 3, "something happened" );

那个 1 为 Log 等级,共有五级:

LEVEL 说明
LEVEL1 fatal error
LEVEL2 important
LEVEL3 average
LEVEL4 below average
LEVEL5 least significant

一般用 3 即可。(现在所有的 log 项都用了 1,以后再修改)


定义完成后,就可以在代码中使用 Logger::log( BCD::DEMO_MODULE::SOMETHING, "optional remarks" ) 来 log。


补充说明:

  • 可参考 UR 模块 Log 的定义、使用。

如果只测试自己的模块,想要在程序退出时自动保存,需要在 main.cpp 中加入:

// #include "logger.h"
// #include <stdlib.h>
atexit( (void(*)())Logger::save );

编码问题,在 main.cpp 里加入:

// after define guard
#if _MSC_VER >= 1600
#pragma execution_character_set( "utf-8" )
#endif

// in main function
QTextCodec::setCodecForTr( QTextCodec::codecForName( "UTF-8" ) );
QTextCodec::setCodecForCStrings( QTextCodec::codecForName( "UTF-8" ) );
QTextCodec::setCodecForLocale( QTextCodec::codecForName( "UTF-8" ) )

// three ways
Logger::log( BCD::LMS::LMS, "cstr 中文" );
Logger::log( BCD::LMS::LMS, QString("QString 中文") );
Logger::log( BCD::LMS::LMS, std::string("string 中文") );
#!/bin/bash
# pandoc CodingStyleOfChangshaTeam_CVRS.md -o CodingStyleOfChangshaTeam_CVRS.docx
git add -A && git commit -m 'done' && git push
``` cpp
/*
return:
-1: error
1: success
*/
int writeGisData( const _image *im );
//! configure VS execution character set to UTF-8
#if _MSC_VER >= 1600
#pragma execution_character_set("utf-8")
#endif
//! configure Qt codec to UTF-8
QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8"));
QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));
```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment