C¶
编码规范¶
优秀编码码准则¶
- 维护性:一般需要解耦合度,降低各功能代码块间的耦合度
- 复用性:需要将各功能代码块进行封装,用到时直接调用
- 扩展性:需要应用类的可继承性。或者配合使用工厂模式,让工厂根据不同的情形实例化不同功能的对象。
- 灵活性:需要满足以上三个特性,然后考虑实现跨平台ARM x86,可移植性等。
- 健壮性:考虑各异常情况,尽量使代码任何时候都能工作,否则抛出异常
- 可读性:例如if else 嵌套不要超过三层。语法不要复杂嵌套,例如多级指针
NASA 安全代码规范¶
- 将所有代码限制为非常简单的控制流结构,不要使用goto语句、setjmp 或 longjmp 构造以及直接或间接的递归调用
- 所有循环都必须有一个固定的上界。
- 初始化后不要使用动态内存分配。
- 任何函数都都不应超过可以打印在单张论文纸上的长度,每条语句一行,每条语句一行声明。通常,这意味着每个函数不超过 60 行代码。
- 每个函数的断言,至少要有两个。
- 数据对象必须在尽可能小的范围内声明
- 函数的返回值和函数的形参有效性必须做检测。
- 预定义宏限用于包含的头文件和简单的宏定义。
- 指针的使用应该受到限制。具体来说,不超过一级指针。指针解引用操作不能隐藏在宏中定义或在 typedef 声明中。不允许使用函数指针(使用函数指针后,分析功能可能无法检测是否有递归问题)。
- 从编写代码的第1天开始,编译器的所有编译警告设置要全开,所有的代码编译后必须零警告,并且使用静态分析工具分析后,也必须保证零警告。
C语言编程¶
static关键字¶
经验累积¶
使用枚举类型,增加代码可读性¶
//状态机状态枚举
enum
{
uint8 STATE1 = 1,//递增
uint8 STATE2,
uint8 STATE3,
uint8 STATE4,
uint8 STATE5,
}State_Type;
使用结构体,描述对象¶
例如描述ModbusRTU的协议帧
typedef struct
{
uint8 device_addr;//从机地址域
uint8 func_code;//功能码
uint8 data[];//数据域
uint8 CRC_L;
uint8 CRC_H;
}ModbusRTU_Frame;
使用MAP思想映射,记录数据¶
例如,通过ascii值记录出现过的字母,以及出现过的频次
使用MASK思想,记录标志位¶
例如,一个16位的数据类型,uint16。可以使用位操作对16个位赋予1/0状态。用于标记状态位
C数据结构¶
链表¶
以下代码均以带头节点的链表为例子
//链表初始化
LinkList InitList()
{
LinkList L=(LNode *)malloc(sizeof(LNode)); //为头结点动态分配内存
L->next=NULL; //初始化时头结点指向空
return L;
}
//插入
//头插法:插入数据逻辑简单,但是插入数据与在链表中的排序顺序相反
void HeadInsertList(LinkList L,int data)
{
scanf("%d",&data);
LNode *p=(LinkList)malloc(sizeof(LNode));
p->val=data;
p->next=L->next;
L->next=p;
}
//尾插法:相对于头插法来说,数据的插入顺序与在链表中的数据顺序时一致的
void EndInsertList(LinkList L,int data)
{
LNode *End;
End=L;
while(End->next)
{
End=End->next;
}
LNode *p=(LinkList)malloc(sizeof(LNode));
p->val=data;
End->next=p;
p->next=NULL;
}
//遍历
void TraverList(LinkList L)
{
LNode *p=L->next;
while(p) //由于最后的节点指向空,可以通过这一特点结束遍历
{
printf("%d ",p->val);
p=p->next;
}
}