程序设计风格

112 阅读4分钟

1命名风格
(1)名字要准确表达用途

 #define ONE 1
 #define TEN 10
 #define TWENTY 20
 
 #define INPUT_MODE 1
 #define INPUT_BUFSIZE 10
 #define OUTOUT_BUFSIZE 20

(2)名字不是越长越好。全局变量可以用具有描述意义的长名字; 局部变量用短名字会显得程序更简洁

 for (elementIndex = 0; elementIndex < numberOfElements;elementIndex++)
      elementArray[elementIndex] = elementIndex;
 for (i = 0; i < nitems; i++)
      elem[i] = i;
      

(3)类的成员的名字,不要再啰嗦重复类名。

 Class UserQueue{
    int numOfItemsInQ, frontOfQueue, queueCapacity;
    public int numOfUsersInQueue() {...}
 }
 Class UserQueue{
    int nUsers, front, capacity;
    public int getNumOfUsers() {...}
 }
 

(4)用动词或者动词+名词定义函数名。

  now = date.getTime()
  putchar('\n')
  

(5)返回布尔值的函数名应该是一个命题,通常使用is作为函数名中的动词。

  #define checkoctal(c) ((c) >= '0' && (c) <= '7')
  if (checkoctal(x))...

  #define isoctal(c) ((c) >= '0' && (c) <= '7')
  if (isoctal(x))...
  

(6)名字尽可能简单明了,不要用“否定之否定”。

  bool not_eof = true
  if((ch = getchar()) == EOF)
    not_eof = false;
  bool is_eof = false;
  if((ch = getchar()) == EOF)
    is_eof = true;
                                           

2表达式和语句
(1)使用表达式的自然形式,即常见的易于理解的形式。

   if(!(block_id < actblks) || !(block_id >= unblocks))...
   if((block_id >= actblks) || (block_id < unblocks))...
    

(2)利用括号排除歧义。即使语法上不要求括号,也建议加上括号以便提高代码可读性

   #define MASK 0x0F
   #define BITS 0x01
   if(x & MASK == BITS)...
   #define MASK 0x0F
   #define BITS 0x01
   if((x & MASK) == BITS)...
   

(3)分解复杂的表达式。

    *x += (*xp = (2 * k < (n - m) ? c[k + 1] : d[k--]));
    if (2 * k < (n - m))
        *xp = c[k + 1];
    else
        *xp = d[k--];
    *x += *xp

3一致性和习惯用法
(1)使用一致的缩进和花括号风格(例如两行以上一定加花括号)

     if(month == FEB){
        if(year%4 == 0)
           if(day > 29)
              legal = FALSE;
        else
          if(day > 28)
             legal = FALSE;
      }
      if(month == FEB){
         if(year%4 == 0){
            if(day > 29)
               legal = FALSE;
         }else{
             if(day > 28)
                legal = FALSE;
         }

       }
       

(2) 使用大多数人最习惯用法。(for循环设计的目的,就是让循环的起始状态,结束条件和步长一目了然)

     i = 0;
     while(i <= n-1)
     array[i++] = 1.0;
                   
     for(i = 0; i < n; )
     array[i++] = 1.0;
     for(i = n; --i >= 0; )
     array[i] = 1.0;
     for(i = 0; i < n; i++)
     array[i] = 1.0;
                    

(3)用else-if 处理多路选择,一个判断应尽可能接近它所对应的动作

     if(argc == 3)
        if(fin = fopen(argv[1], "r")) != NULL)
           if(fout = fopen(argv[2], "w")) != NULL){
              while((c = getc(fin)) != EOF)
                 putc(c, fout);
              fclose(fin);
              fclose(fout);
           }else
              printf("Can’t open output file %s\n",argv[2]);
       else
         printf("Can’t open input file %s\n", argv[1]);
     else
         printf("Usage: cp inputfile oputputfile\n");

    if(argc != 3)
       printf("Usage: cp inputfile oputputfile\n");
    else if(fin = fopen(argv[1], "r")) == NULL)
      printf("Can’t open input file %s\n", argv[1]);
    else if(fout = fopen(argv[2], "w")) != NULL){
      printf("Can’t open output file %s\n", argv[2]);
      fclose(fin);
    }else{
       while((c = getc(fin)) != EOF)
          putc(c,fout);
       fclose(fin);
       fclose(fout);
    }

3函数宏
(1)函数宏的缺点,直接替换,导致用到两次的参数会被替换两次,执行两次,可能直接导致错误。

    #define isupper(c) ((c) >= 'A' && (c) <= 'Z')
    while(isupper(c = getchar()))...
    #define isupper(c) ((c) >= 'A' && (c) <= 'Z')
    // 宏替换后的样子
    while((c = getchar()) >= 'A' && (c = getchar()) <= 'Z')...
   /*** ctype.h中定义的isupper更好***/
   #define __isctype(c, type) \
      ((*__ctype_b_loc())[(int)(c)] & (unsigned short)type)
   #define isupper(c) __isctype((c), _ISupper)
   /*** 避免isupper的参数中写很多东西 ***/
   while((c = getchar()) != EOF && isupper(c))...
                                                          

(2)函数宏的缺点,直接替换,导致用到两次的参数会被替换两次,执行两次,也可能导致性能问题

#define ROUND_TO_INT(x) ((int)((x)+(((x)>0)?0.5:-0.5)))
size = ROUND_TO_INT(sqrt(x));
// 宏替换之后的样子
size = ((int)((sqrt(x)+(((sqrt(x)>0)?0.5:-0.5)))
int round_to_int(float x)
{
   return (int)(x + ((x > 0) ? 0.5 : -0.5));
}
size = round_to_int(sqrt(x));

(3)如果一定要用函数宏,不要吝啬括号

   #define square(x) (x) * (x)
   y = 1 / square(x)
   // 宏替换之后的样子
   y = 1 / (x) * (x)
  #define square(x) ((x) * (x))
  y = 1 / square(x)
  // 宏替换之后的样子
  y = 1 / ((x) * (x))

4注释
(1)注释的目的是解惑,而不是增加疑惑。注释与代码要始终保持一致

     if((country == SING) || (country == BRNI) ||
        (country == POL) || (country == ITALY))
      {
        /* If the country is Singapore, Brunei or Poland
         * then the current time is the answer time
         * rather than the off hook time
         * Reset answer time and set day of week
       */
        ...
      }

(2)不要写没用的注释。

      /* if "result" is 0 a match was found so return true
         Otherwise, "result" is non-zero so return false */
      return (!result)

      return matchFound;

(3)用好的命名代替注释。

(4)用注释自动生成文档