返回介绍

C代码规范

发布于 2024-10-04 12:28:35 字数 17353 浏览 0 评论 0 收藏 0

0x04 C代码规范

  1. 命名

    • 只要提到代码规范,就不得不说的一个问题。
    • 在一些小的演示程序中,也许费尽心思去构思一个 命名 是一件十分傻的行为,但是只要程序上升到你需要严正设计,思考,复查的层次,你就需要好好考虑 命名 这个问题。
    • 函数命名:

      • C语言中,我们可以让下划线或者词汇帮助我们表达函数功能:

        1. 前缀:
          1. set 可以表示设置一个参数为某值
          2. get 可以表示获取某一个参数的值
          3. is 可以表示询问是否是这种情况
        2. 后缀:

          1. max/min 可以表示某种操作的最大(小)次数
          2. cnt 可以表示当前的操作次数
          3. key 某种关键值

             size_t get_counts();
             size_t retry_max();
             int    is_empty();
            
      • 需要注意的只是,不要让命名过于赘述其义,只简单保留动作以及目的即可,详细功能可以通过文档来进行进一步的解释。
    • 结构体命名:

      • 由于结构体的 标签,不会污染命名,即标签不在命名搜索范围之内,所以可以放心使用:

        1. 有人习惯使用 typedef, 而有人喜欢使用 struct tag obj,后者比较多,但是前者也不失为一种好方法,仁者见仁智者见智。

           /*方法1*/
           struct inetaddr_4{
                   int    port;
                   char * name;
           };
           struct inetaddr_4 *addr_info;
           /*方法2*/
           typedef struct _addr{
                   int    port;
                   char * name;
           }inetaddr_4;
           inetaddr_4 *addr_info_2;    
          

          两者同处一个文件内亦不会发生编译错误。

    • 变量命名

      • 所有字符都使用小写
      • 含义多的可以用 _ 进行辅助
      • = 为标准进行对齐
      • 类型, 变量名左对齐。
      • 等号左右两端,最少有一个空格。

          int main(void)
          {
              int          counts = 0;
              inetaddr_4   *addr    = NULL;
        
              return 0;
          }
        

        为了防止指针声明定义时候出错,将 * 紧贴着变量名总不会出错。

          inetaddr_4   *addr, object, *addr_2;
        

        其中 addraddr_2 是指针,而 object 则是一个栈上的完整对象,并不是指针。

      • 全局变量能少用就少用,必须要用的情况下,可以考虑添加前缀 g_

          int g_counts;
        
    • #define 命名

      • 所有字符都是用大写,并用 _ 进行分割
      • 如果多于一个语句,使用 do{...}while(0) 进行包裹,防止 ; 错误。

          #define SWAP(x, y)         \
          do{                        \
              x = x + y;        \
              y = x - y;            \
              x = x - y;            \
          }while(0)
        

        当然这个交换宏实际上有一点缺陷,在大后方会提出。此处是代码规范,就不重复强调。

    • enum 命名

      • 所有字符都是用大写,并用 _ 进行分割
      • define 相比,enum适用于同一类型的常量声明,而不是单一独立的常量。往往出现都是成组。
  1. 格式化代码

    • 花括号 {}

      • 混合使用符合节俭思想,但会稍微有一点结构紊乱。
      • 单一使用能更好让代码结构清晰。
      • 所谓混合,单一指的是是否一直使用 {} 进行代码包裹。
      • 有人认为 当单一语句的时候不必要添加 {},有的人则习惯添加
      • 当作用域超过一个屏幕的时候,可以适当的使用注释来指明 {} 作用域

          while(1){
              if(tmp == NULL){
                  break;
              }
              else if(fanny == 1){
                  ... 大概超过了一个屏幕的代码
              } /*else if fanny*/
          }/*end while*/
        

        如果是代码量少的情况下,但嵌套比较多,也可以使用这个方式进行注释。

    • 括号 ()

      • 有人建议除了函数调用以外,在条件语句等类似情况下使用 () 要在关键字后空一格,再接上 ()语句,对于这一点,我个人习惯是不空格,但总有这种说法。

          if (space == NULL) {
              /**TODO**/
          }
          while(1){
              /**我习惯于如此写**/
          }
          strcpy(str1, str2); /**第一种写法是为了和函数调用写法进行区分**/
          return 0;
        
    • switch

      • 一定要放一个 default 在最后,即使它永远不会用到。
      • 每个 case 如果需要使用新变量,可以用 {} 包裹起来,并在里面完成所有操作。

          switch(...)
          {
              case 1:
                  /**TODO**/
                  break;
        
              case 2:
              {
                  int new_vari;
                  /**创建新变量则用 {} 包裹起来**/
              }
              break;
        
              default:
                  call_error();
          }
        
    • goto

      • 虽然许多人,许多书都提醒不再使用 goto 关键字,而是使用 setjmplongjmp来取代它,但是这还是那句话,仁者见仁智者见智,如果 goto 能够让代码清晰,那何乐而不为呢,这个观点也是最近才体会到的(并非我一己之言)。
      • 具体使用可以查询官方文档。
    • 语句

      • 应该让完整的语句在每一行中,只出现一次。
      • 对于变量声明定义亦是如此
      • 原因是这样能让文档更有针对性
    • 头文件保护

      • 对于头文件而言,在一个程序中有可能被多次包含(#include),如果缺少头文件保护,则会发生编译错误
      • 不要将 _ 作为宏的开头或者结尾。

          #ifndef VECTOR_H_INCLUDE
              #define VECTOR_H_INCLUDE
                  /**TODO**/
              #endif 
        
    • C语言的宏有诸多弊端,所以尽量使用 inline 函数来代替宏。在大后方会有解释
    • 但是,请不要因此抛弃了宏,比如在 C11 中有一个新兴的宏。
  2. 变量

    • 第一时刻初始化所有所声明的变量,因为这么做总没有坏处,而且能减少出错的可能。
  3. 函数

    • 函数应该尽可能的短小,一个ANSI屏幕的为最佳。
  4. 如果某个循环带着空语句,使用 {} 进行挂载,以免出现意外。

     while(*is_end++ != '\0')
     {
         ;
     }
    

    虽然是空的循环体,但是写出来以免造成误循环。

  5. 尽量不要让函数返回值直接作为条件语句的判断,这样会极大降低可读性

     if(is_eof(file) == 0)
         好过
     if(!is_eof(file))
    
  6. 不要为了方便或者一点点的所谓速度提升(也许根本没有),而放弃可读性,使用嵌入式的赋值语句

     int add = 10;
     int num = 11;
     int thr = 20;
     add = add + thr;
     num = add + 20;
         不要写成
     num = (add = add + thr) + 20;
    

浮点数

  • 万万记住不要再使用浮点数比较彼此是否相等或不等。
  • 如果把浮点数用在离散性的数据上,比如循环计数器,那就等死吧。

其他

  • 使用 #if 而不是 #ifdef
  • 可以使用 define() 来代替 #ifdef的功能

      #if !define(USERS_DEFINE)
          #define USERS_DEFINE ...
      #endif
    
  • 对于某些大段需要消除的代码,我们不能使用注释 /**/,因为注释不能内嵌着注释(//除外),我们可以使用黑魔法:

      #if NOT_DECLARATION
          /**想要注释的代码**/
      #endif
    
  • 不要使用纯数字

    • 意味着,不在使用毫无标记的数字,因为可能你过了几个月再看源代码的时候,你根本不知道这个数字代表着什么
    • 而应该使用#define 给它一个名字,来说明这个数字的意义。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文