[关闭]

CVRS C++ Coding Style 规范

WHU-CVRS Team

Read online: http://cvrs.whu.edu.cn/docs/CVRS-CodingStyleGuide.html


零、绪论

  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 便可直接当成类型使用,也就是说,下面两种是一样的

  1. // method 1
  2. struct ElecStateStruct {
  3. char *elec_name;
  4. char *elec_state;
  5. };
  6. // method 2
  7. typedef struct ElecStateStruct {
  8. char *elec_name;
  9. char *elec_state;
  10. } ElecStateStruct;

但推荐使用第二种

命名规则和类的一样。

4)函数和变量:

函数:

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

变量:

  1. 定义声明:与 C 一致。
  2. 命名规则:全局(e.g. _currentTemperature),局部(e.g. currentTemperature),函数内部的变量可以尽可能短。

5)宏:

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

三、程序排版规则

原则 0:

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

原则 1:

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

C Example:

  1. #include <stdio.h> // <-- 注意这里 <stdio.h> 前的空格
  2. #include <math.h>
  3. // <-- 【#include】s 后空行
  4. #define PI (3.1415) // <-- 最好都加上括号
  5. typedef struct PointCoordinate
  6. {
  7. int x ;
  8. int y;
  9. } Point;
  10. //! setting coordinate // <-- 函数说明
  11. Point set_point( int a, int b ); // <-- 函数声明,参数列表这里有空格
  12. //! get the area of the circle
  13. double get_area( int radius );
  14. void main()
  15. {
  16. // define the coordinate of the center, the radius and the area of a circle
  17. Point point_circle; // <-- 变量定义规则:小写,之间加下划线
  18. int radius_circle;
  19. double area_circle;
  20. // input the information of a circle // <-- 函数部分步骤意义说明规则
  21. printf( "please input point.x & point.y: \n" ); // <-- 函数调用,参数列表这里有空格
  22. scanf( "%d%d", &point_circle.x, &point_circle.y );
  23. printf( "please input the radius of the circle:\t" );
  24. scanf( "%d", &radius_circle );
  25. area_circle = PI * radius_circle * radius_circle;
  26. printf( "the area of a circle is: %lf\n", area_circle );
  27. }
  28. Point setPoint( int a, int b ) // <-- 函数定义,参数列表这里有空格
  29. {
  30. Ponit pt;
  31. pt.x = a;
  32. pt.y = b;
  33. return pt;
  34. }
  35. double getArea( int radius )
  36. {
  37. double S;
  38. S = PI * radius * radius;
  39. return S;
  40. }

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

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

C++ Example:

  1. #include <iostream>
  2. #define PI (3.1415)
  3. #define MAX (300)
  4. //! basic class,2dim_point // <-- 对类的说明
  5. class Point
  6. {
  7. private:
  8. int x;
  9. int y;
  10. public:
  11. int getX( ) { return x; } // <-- 极其简单的函数,可以放在一行
  12. int getY( ) { return y; }
  13. //! setting coordinate // <-- 函数说明(这个函数,就不该放在一行)
  14. void setPoint( int a, int b )
  15. {
  16. x = a;
  17. y = b;
  18. }
  19. };
  20. //! derived class circle
  21. class Circle : public Point
  22. {
  23. private:
  24. //! radius of a circle // <-- 变量说明格式
  25. int radius;
  26. public:
  27. //! set the size of the radius
  28. int setRadious( int r ) { radius = r; }
  29. void getRadious( ) { return radius; }
  30. //! get the area of the circle
  31. double getArea( ) { return PI * radius * radius; }
  32. };
  33. void main( )
  34. {
  35. // define a circle
  36. Circle circle1;
  37. // set up circle center & radius // <-- 对程序中的部分步骤说明
  38. circle1.setPoint(200, 250);
  39. circle1.setRadius(100);
  40. // output the X coordinate of the center of the circle1
  41. cout << "x = " << circle1.getX() << endl;
  42. // output the X coordinate of the center of the circle1
  43. cout << "the Area of Circle1 is " << circle1.getArea() << endl;
  44. }

正确和错误举例

  1. /*
  2. * 加足够的空格
  3. **/
  4. for(int i;i<count;i++) // WRONG
  5. for ( int i; i < count; i++ ) // CORRECT
  6. for ( int i; i < count; ++i ) // EVEN BETTER
  7. int max(int a,int b) // WRONG
  8. int max( int a, int b ) // CORRECT
  9. max(23,45); // WRONG
  10. max(23, 45); // WRONG
  11. max( 23, 45 ); // CORRECT
  12. max( 21, max(max(3,8), 34) ); // CORRECT,只是举例例子,体会一下这些空格的有无
  13. /*
  14. * 大括号的位置
  15. **/
  16. for ( int i; i < count; ++i ) // CORRECT,注意这里的空格
  17. {
  18. ...
  19. }
  20. for ( int i; i < count; ++i ) { // CORRECT
  21. ...
  22. }
  23. // 同理,正确的 while,if,do while 应为
  24. while ( CONDITION ) {
  25. ...
  26. }
  27. while ( CONDITION )
  28. {
  29. ...
  30. }
  31. if ( CONDITION ) {
  32. ...
  33. }
  34. if ( CONDITION_1 ) {
  35. ...
  36. } else if ( CONDITION_2 ) {
  37. ...
  38. } else {
  39. ...
  40. }
  41. do {
  42. ...
  43. } while ( CONDITION );
  44. /*
  45. * 永远都加 {},哪怕只有一行代码,适用于 if、for、while 和函数声明+定义
  46. **/
  47. if ( FATAL_ERROR ) // WRONG
  48. return EXIT_FAILURE;
  49. if (FATAL_ERROR) { // CORRECT
  50. return EXIT_FAILURE;
  51. }
  52. int getX( ) return x; // WRONG,不知道有没有 syntax error,但看上去就不好
  53. int getX( ) { return x; } // CORRECT
  54. /*
  55. * 函数声明和调用的参数规范
  56. **/
  57. void func(); // WRONG
  58. void func2(int i, int j);
  59. void func( ); // CORRECT
  60. void func2( int i, int j );

一些例子:

  1. // 1
  2. bool p = isPrime(23) ? true : false;
  3. bool p = isPrime(23)
  4. ? true
  5. : false;
  6. // 2, TODO

其他一些说明

注释的放置

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

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

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

  1. fprintf( fp,
  2. "| %*i " // index
  3. "| %*s " // timestamp
  4. "| %*s%d%*s " // log level
  5. "| %*s%s%*s " // type (aligned to center)
  6. "| %-*s " // action
  7. "| %*s |\n", // messag
  8. ... );

对齐

通常不需要对齐,比如:

  1. int x0;
  2. double dx;

不必写成:

  1. int x0;
  2. double dx;

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

  1. /*
  2. * 对齐实例 1
  3. **/
  4. ust.time = parse8BytesToDouble(ba, c, f); c += 8;
  5. // q target
  6. ust.q_target[0] = parse8BytesToDouble(ba, c, f); c += 8;
  7. ust.q_target[1] = parse8BytesToDouble(ba, c, f); c += 8;
  8. ust.q_target[2] = parse8BytesToDouble(ba, c, f); c += 8;
  9. ust.q_target[3] = parse8BytesToDouble(ba, c, f); c += 8;
  10. ust.q_target[4] = parse8BytesToDouble(ba, c, f); c += 8;
  11. ust.q_target[5] = parse8BytesToDouble(ba, c, f); c += 8;
  12. /*
  13. * 对齐示例 2
  14. **/
  15. enum URFunctionCodes { /* 0-128d */
  16. // mb_req_pdu
  17. READ_COILS = 0x01, // read output bits
  18. READ_DISCRETE_INPUTS = 0x02, // read input bits
  19. READ_HOLDING_REGISTERS = 0x03, // read output registers
  20. READ_INPUT_REGISTERS = 0x04, // read input registers
  21. };
  22. /*
  23. * 对齐示例 3
  24. **/
  25. mcuAddr.insert( ROLL_PITCH_YAW, 0x000B );
  26. mcuAddr.insert( accX_accY_accZ, 0x000E );
  27. mcuAddr.insert( GyroscopeX, 0x0011 );

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

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

而是使用:

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

参数列表也要对齐:

  1. // method 1
  2. return QString().sprintf( "%02d:%02d:%02d.%03d" // e.g. 01:23:45.678
  3. , dt.time().hour()
  4. , dt.time().minute()
  5. , dt.time().second()
  6. , dt.time().msec() );
  7. // method 2
  8. return QString().sprintf( "%02d:%02d:%02d.%03d", // e.g. 01:23:45.678
  9. dt.time().hour(),
  10. dt.time().minute(),
  11. dt.time().second(),
  12. dt.time().msec() );
  13. // but not this one
  14. return QString().sprintf( "%02d:%02d:%02d.%03d", // e.g. 01:23:45.678
  15. dt.time().hour(), dt.time().minute(),
  16. dt.time().second(), t.time().msec() );
  17. // and, of course, not this one
  18. return QString().sprintf( "%02d:%02d:%02d.%03d", dt.time().hour(),
  19. dt.time().minute(), dt.time().second(), t.time().msec() );
添加新批注
回复批注