• 如何写出高质量的C代码?快来学习这些coding技巧


    前言

    世界上有两种程序员:一种是草草写完代码然后化身苦逼程序猿苦苦寻找bug;另一种是上手就写出高质量的代码化身bug终结者。优秀的程序员往往将bug扼杀在萌芽中,很明显这是“另一种”程序猿,那么我们应该怎样写出一手高质量的优秀代码呢?

    一、优秀的代码

    什么是优秀的代码?优秀的代码具有以下特点:

    1. 代码运行正常
    2. bug很少
    3. 效率高
    4. 可读性高
    5. 可维护性高
    6. 注释清晰
    7. 文档齐全

    二、常见coding技巧

    当然了,想要写出以上优秀的代码,需要我们在编码时刻意的去使用一些编码技巧,例如一些常见的coding技巧:

    1. 使用assert
    2. 尽量使用const
    3. 养成良好的编码风格
    4. 添加必要的注释
    5. 避免编码的陷阱

    现在大家可能还体会不到这些coding技巧带来的实际意义,下面就以实例向大家演示:

    三、模拟实现库函数:strcpy

    我们已知库函数strcpy的作用是将含有'\0'结束符的字符串复制到另一个地址空间。根据它的功能,我们利用指针偏移模拟复刻出以下代码:

    虽然上述代码也可以模拟实现出strcpy函数的功能,但是这是一种非常不好的代码风格。我们应该怎样对其优化呢?

    1、优化一:字符复制和‘\0’复制的整合

    初代代码,我们将内容复制和最后‘\0’的复制功能分离,对此我们可以将二者功能整合,使代码更巧妙紧凑。

    2、优化二:使用assert

    在拷贝函数中我们对指针进行了解引用等相关操作,但是如果在传参过程中不小心传入了一个空指针呢?我们知道空指针是不能进行这些操作的,一但传入空指针该程序就会崩掉,并且我们不知所以然,还要通过调试一步一步的去定位错误。为了能够很好的预防和避免以上问题,我们可以在程序中添加assert函数:

    这里我们假设无意中传入一个空指针,看看会出现什么效果:
    屏幕上输出:Assertion failed:src-断言错误: src,我们可以根据提示,追根溯源一步步锁定错误。

    同样都是判断,为什么不使用if语句呢?
    if语句在Debug版本和Release版本都会被执行,而assert仅在Debug版本中执行,在Release版本中会被优化掉。综上来看,assert是对程序员非常友好的一个库函数。

    3、优化三:const修饰


    观察库函数的特征,函数中存在一个const修饰的指针变量,这里的const又有什么样的作用呢?下面我们通过以下三种代码的可执行情况来分析:


    const修饰指针变量的时候:

    1. const如果放在*的左边,修饰的是指针指向的内容,保证指针指向的内容不能通过指针来改 变。但是指针变量本身的内容可变。
    2. const如果放在*的右边,修饰的是指针变量本身,保证了指针变量的内容不能修改,但是指 针指向的内容,可以通过指针改变。

    结合const修饰指针变量的作用,我们对原始数据的指针变量使用const修饰,意味着原始数据不可修改,这里起到了保护原始数据的作用。

    例如:在拷贝数据时我们不小心将*dest++=*src++误写成*src++=*dest++,如果不使用const修饰src,当程序报错后还需一步一步调试从而定位错误,如果使用了const修饰src,我们可以很快在报错信息中定位错误,提高效率。

    4、优化四:添加返回值

    字符串拷贝函数返回的是目标空间的起始地址。

    5、优化五:添加注释

    虽然注释并不参与编译,但是在开发中注释也具有十分重要的作用。

    1. 有助于理解

    2. 帮助修补程序或快速修复

    3. 有助于加快开发过程

    4. 有助于提高协作效率

    //模拟strcpy函数--注释
    
    //功能:
    //char* my_strcpy(char* dest, const char* src)-将字符串src复制到另一个字符串dest上
    //参数:
    //char* dest - 目标字符串
    //const char* src - 要在“dest”上复制的字符串
    //返回值:
    //目标字符串的首元素地址
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    6、最终代码

    //模拟strcpy函数--注释
    
    //功能:
    //char* my_strcpy(char* dest, const char* src)-将字符串src复制到另一个字符串dest上
    //参数:
    //char* dest - 目标字符串
    //const char* src - 要在“dest”上复制的字符串
    //返回值:
    //目标字符串的首元素地址
    
    #include
    char* my_strcpy(char* dest, const char* src)
    {
    	assert(dest);
    	assert(src);
    	char* ret = dest;//用来定位首元素地址
    
    	while (*dest++ = *src++)//既拷贝了内容又能很好的停下
    	{
    		;
    	}
    	return ret;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    7、练习:模拟实现strlen函数

    仿照以上优化思路,我们也可以类似的对库函数strlen进行模拟实现。

    //模拟strlen函数--注释
    //功能:统计字符串长度,不包括‘\0’
    //参数:const char* str-被统计字符串地址
    //返回值:字符串长度,不包括‘\0’
    
    #include
    int my_strlen(const char* str)
    {
    	assert(str);
    	int count = 0;
    	while (*str)
    	{
    		count++;
    		str++;
    	}
    	return count;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    总结

    纸上得来终觉浅,绝知此事要躬行。想要写出优秀的代码,需要我们在编码时刻意的对代码进行研判,学习借鉴好的代码风格,时常总结,积累经验。在这里特别推荐两本可以提高代码质量的书籍:《高质量的C-C++编程》《C陷阱与缺陷》或许在这里面可以找到你想要的更多答案!

  • 相关阅读:
    CSP-J 2022 第一轮试题
    java 闭包的用途是什么
    自定义注解结合SpringAop实现权限,参数校验,日志等等功能
    MyBatisPlus入门
    go语言与c语言调用的方法
    2-2、依赖注入以及特殊属性的赋值
    授予渔,从0开始搭建一个自己想要的网页
    jQuery实现微博发布框@好友出现列表功能
    生成代理:人类行为的交互模拟(Generative Agents: Interactive Simulacra of Human Behavior)
    YOLOv8改进 | 如何在网络结构中添加注意力机制、C2f、卷积、Neck、检测头
  • 原文地址:https://blog.csdn.net/LEE180501/article/details/126507506