找回密码
 立即注册
查看: 903|回复: 2

一份好的代码应当遵循的基本编码规范

[复制链接]
  • 打卡等级:以坛为家II
  • 打卡总天数:456
  • 最近打卡:2025-05-02 08:26:53
已绑定手机

27

主题

341

回帖

1691

积分

金牌会员

机长

积分
1691
发表于 2023-6-15 18:13:08 | 显示全部楼层 |阅读模式
本帖最后由 hsrzq 于 2023-6-16 10:43 编辑

  • 整个项目中的所有代码风格都应当保持一致。例如:要用空格缩进就都用空格,要用Tab缩进就都用Tab……
  • (异议)代码都应当使用utf-8编码格式
  • 同一层级的代码缩进也应当相同;次一级应当比上一级拥有更多缩进;优先使用4个空格代替Tab缩进;尤其要注意成对花括号的对齐。赏心阅目的代码能方便自己和别人查找代码中的问题。
  • 需要时一般的代码块之间可以空一行作为分隔,较大区别或分属不同大块的代码之间可以空两行,但不要出现大段大段毫无意义的空行在那里。
  • 嵌入式开发中的特殊语法如sfr、sbit等应当定义宏,不要直接使用,以方便有需要时方便在keil、iar和sdcc间迁移。
    #if defined (SDCC) || defined (__SDCC)
      #define SBIT(name, addr, bit)  __sbit  __at(addr+bit) name
      #define SFR(name, addr)        __sfr   __at(addr)     name
    #elif defined (__CX51__)
      #define SBIT(name, addr, bit)  sbit  name = addr^bit
      #define SFR(name, addr)        sfr   name = addr
    #endif
  • 对于数字类型int、long等应当定义别名使用,别名应当能够充分体现是否有符号和长度,不要直接使用默认的原始类型。正例:u8、u16
  • 定义类型别名时应当使用typedef而不是#define。原因是#define只是简单的文本替换,可能会产生意想不到的意外效果。
    当使用#define pint (int*)时, pint a, b, c;等同于int* a, b, c;
    当使用typedef int* pint 时,pint a, b, c;等同于int* a; int* b; int* c;
  • 不要直接使用默认的GPIO寄存器名称,应当再定义一个与业务相关的别名使用,以便在需要更换引脚时尽量少修改代码。正例:#define LED P01
  • 一些常量魔术值应当先定义再使用,一般不要直接使用值本身。例如:TMR2_VECTOR一定比12更方便阅读
  • 强烈建议创建一个用于全局配置的头文件,将一些开关、常量等统一在这个头文件中,如当前所使用晶振的频率等。正例:FreeRTOS中的FreeRTOSConfig.h头文件
  • 定时器等的初始值不应当直接使用某个具体数字,而是应当使用全局配置文件中的晶振频率推算。这样方便在修改晶振中心频率后无需修改定时器。
  • 数学运算优先使用位移操作,以尽可能提高代码性能。正例:T2L = BRT; T2H = BRT >> 8; 反例:T2L = BRT % 0xff; T2H = BRT / 0xff;
  • 优先使用定时器、状态机等方式来进行延时,非万不得以不要使用delay方式死等
  • 不要使用单个字母或无意义的单词作为变量名。例外:for循环中的i、j、k;表示坐标的x、y、z。反例:int aaa;
  • 定义变量时习惯性加上默认的初始值,防止意外使用了RAM中不确定的随机值。正例:u8 value = 0;
  • (待定)建议所有变量都加上xdata;非万不得以不要轻易使用pdata;无特殊要求一般不指定data和idata
  • 数组常量表一定要加上code以节省RAM,经典场景如7/8段数码管的编码表、1602/12864的字模表等,通常占用体积巨大并且使用中并不会改变
  • (待定)判断相等时常量在前,可以防止手误将双等号写成单等号,继而误将待判断的变量值改变。反例:if (P11 = 0) 则不仅读不到P1.1端口正确状态,还会将端口状态错误设置成0,并且该if条件将永远也不会为真
  • 不要依赖运算符的优先级,随时可以加括号指定运算顺序。反例:if (x > 0 && y < 0 || x < 0 && y > 0)。正例:if ((x > 0 && y < 0) || (x < 0 && y > 0))
  • 即使只有一条子语句,if/for/while等也不要省略花括号。例外:当使用while(!busy);这种等待标记变化时,是直接用分号将语句结束的,这种情况下可以省略花括号。
  • 代码按照大功能块归属不同来分类,不同的大功能应当拆分到各自文件中,甚至可以各自拆分到不同的文件夹中。正例:usb可以有一个文件夹、spi可以有一个文件夹、i2c可以有一个文件夹……
  • 对于一个大功能块下的方法定义,建议按照初始化→控制写→控制读→数据写→数据读→关闭的顺序组织(或者其它符合该功能/外设一般操作流程的顺序),只要不是随意胡乱放置即可。
  • 不太好理解的代码,或容易记混的sfr赋值等,建议多写上注释。
    /* 开启定时器4中断
    * 0b1000____
    * 0b1_______ : T4R    : 定时器T4开始计数
    * 0b_0______ : T4_C/T : 定时器/计数器选择
    * 0b__0_____ : T4x12  : 对系统时钟12分频
    * 0b___0____ : T4CLKO : 关闭定时器的输出
    */
    T4T3M = (T4T3M & 0x0f) | 0x80;

compiler.h

10.03 KB, 下载次数: 59

Keil、SDCC兼容用头文件

业余撸代码,专业开飞机
回复

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:469
  • 最近打卡:2025-05-02 11:38:17

44

主题

230

回帖

2845

积分

金牌会员

积分
2845
发表于 2023-6-15 22:51:51 | 显示全部楼层
第5条的用法在platformIo 网友提供的stc8系列的头文件中看到过。
不争是争
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:139
  • 最近打卡:2024-05-24 15:33:43

13

主题

52

回帖

1428

积分

金牌会员

积分
1428
发表于 2023-6-22 14:20:45 来自手机 | 显示全部楼层
归纳的好。学习了。
回复 支持 反对

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|小黑屋|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2025-5-2 13:10 , Processed in 0.111357 second(s), 66 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表