1 循环
1.1 for循环
禁止修改循环条件和步进长度
for循环的基本框架结构如下,
for (i = start; i < end; ++i)
{
/* In this area, user shall not change end and i*/
}
在该框架下,end的值应该是确定的不可变,即在循环过程中不能更改循环结束条件。同时,i的值也不应该在循环体中被改变。如果确实需要在循环过程中修改end或i的值,请选择使用while循环。
少用--
for循环按照步进方向可以分为两种写法,
/* Increasing circulation */
for (i = start; i < end; ++i)
/* Decreasing circulation */
for (i = end-1; i >= start; --i)
但在实际实践中,还是要尽量避免--的写法,特别是在嵌入式底层开发中。在下述例证中,该for循环会由于无法达到0,从而陷入死循环中
1 for (unsinged char i=50; i>=0; i--)
死循环的最好选择
在某些场景下,需要使用死循环语句,特别是主程序循环。死循环有两种写法,最好还是选用for循环,因为该语句编译器通常不会有警告。但是死循环在程序中通常都是危险的行为,如果需要死循环,请加以注释说明。
1 for(;;) {}
2 while(1) {}
1.2 do-while
在实际的编程中,do-while语句的使用场景有限,因为该结构的循环特性与for、while不一致,使用不仔细或者按照for、while的习惯使用,可能引入隐性BUG。不过在如下场景中,do-while语句却是十分重要。该语句将do-while部分的代码打包成一个整体,在宏替换时,可以保证内部语句执行完整,且不受外部使用的影响。
1 #define MEMEM_DIM2_FREE(data) do {2 MEM_FREE(data.UserPtr);3 MEM_FREE(data.PhyPtr);4 } while(0)
另一个重要的使用方式就是需要随意终止执行流的场景中。

1 do {
2 if (condition1 < condition2)
3 {
4 break;
5 }
6
7 ...
8
9 if (condition3 < condition4)
10 {
11 break;
12 }
13 } while(0);
View Code
1.3 while
嵌入式编程追求的是尽可能高的确定性,因此建议优先使用for循环。如果不适合使用for循环的场景,选择使用while循环。
2 注释选择
目前C语言有两种注释方式,使用//或/**/。
1 // This is comments.
2 /* This is comments. */
在高可靠性编程中,建议使用/**/,禁用//。因为/**/注释有开始和结束位置,而//是开放性语句。同时,/**/的写作负载高于//,使用//可以很轻易的注释一条语句,而该语句到底是否应该被注释,对于阅读代码的人来说是一种负担。
如果需要连续注释,建议/**/的注释写作如下格式,
1 /*
2 * This is comments.
3 */
关于注释位置问题,建议优先选择在语句上方进行注释,少用或者不用尾注释。代码的一个重要作用给程序员阅读,因此整体一致的风格往往能提高阅读舒适度。
1 /* Init modulation parameter */
2 Demo_FunInit(Demo_SystemData);
3 条件判断
对于不少于一个else if的语句,一定需要有else语句,哪怕这条语句没有不执行任何操作。这样做的目的是在多判断条件下,有else表明设计者认为所有条件已经考虑清楚。而没有else语句,代码阅读者不确定设计者是否考虑完所有的判断情况。
1 if (condition1 < condition2)
2 {
3 ...
4 }
5 else if (condition3 < condition4)
6 {
7 ...
8 }
9 else
10 {
11 /*do nothing*/
12 }
对于范围判断,可以使用if-else结构,但是如果是单值判断,建议替换为switch-case结构。
1 /*Bad practice*/
2 if (val == 1)
3 {
4 ...
5 }
6 else if (val == 10)
7 {
8 ...
9 }
10 ...
代码可以修改为,

1 /* Good pratice */
2 switch (val)
3 {
4 case 1:
5 ...
6 case 10:
7 ...
8 ...
9 }
View Code
4 switch-case
switch-case的基本句式为,

1 switch (val)
2 {
3 case condition1:
4 ...
5 break;
6 case condition2:
7 ...
8 break;
9
10 ...
11
12 default:
13 ...
14 break;
15 }
switch-case
善用switch语句,可以增加代码的条理性,在某些场景下也能提高代码执行效率。需要注意,在所有switch-case中都必须有default路径。
如果有可能,用表驱动的方式替换switch-case语句,可以让代码更加简单。
5 变量
5.1 局部变量
局部变量必须初始化,这样能避免由于使用未初始化变量而引入的稀奇古怪的问题。
局部变量使用统一而区别于全局变量的命名方式。
禁止使用汉语拼音构建变量名称。
变量命名应该能体现变量的实际意义。
如果变量占用内存过大,应考虑将该变量转变为全局变量或使用动态内存分配方式,防止栈溢出。
遵守C语言编译规则,变量定义应该在作用域的开始位置;遵循C++规则,可以在使用之前定义。如果代码要在不同的环境中编译,建议遵循C语言规则。
过多的局部变量可能意味着过长的代码或过于复杂的代码,此时需要考虑将函数拆分。
5.2 局部静态变量
虽然部分教程列举了局部静态变量相对于全局变量的优点,但在工程实践中,请禁用局部静态变量。
在高安全高可靠性领域的应用中,要求变量定义在特定的内存区域中,用于数据保护,此时局部静态变量对于这种场景而言是灾难性的存在。
在高性能领域,并发往往是常见的需求,此时局部静态变量就是暗藏的炸弹。
5.3 全局变量
全局变量应限制在模块内使用,禁止在模块之间使用。例如ADC模块定义一个全局变量Adc_GlobalRegBuffer,该变量可以在Adc.c,Adc_Hardware.c中使用,但不能在Dio.c中使用。
在同一个模块中,只定义一个全局变量,全局变量的类型是结构体。模块中使用的全局变量均定义在该结构体中,当调试时拉一个变量就能观测到整个模块的运行状态。同时,这种构建方式,也方便定义变量在内存中的位置,或者将其转为局部变量。
C编程实践——句柄设计
原文:https://www.cnblogs.com/lyndon-jiang/p/14617801.html