函数式编程要归结于一句话:
高内聚,松耦合,高扇入,合理扇出
高内聚:
内聚是函数内各个元素彼此结合的紧密程度。越紧密代表了函数的独立性越强。
松耦合:
耦合是一个软件结构内不同函数之间互连程度的度量,耦合性也叫块间联系。模块之间尽量有紧密联系
高扇入:
扇入是一个函数被其他函数调用的次数。被调用越多代表这个函数价值越高
合理扇出(<7):
扇出是一个函数内部调用其他函数的次数,调用函数越多,当其中一个函数变化时会影响被调用函数。
嵌入式c也是有单元测试的,例如 CUnit,主要是断言和log显示结果~~以后再分析
公司采用的都是华为规范来进行代码测评
1,逻辑连接符需加括号
extern BOOL get_bool ( void );
void static_49(void)
{
BOOL flag = TRUE;
INT_32 y = 0, x = 0, z = 1;
if (x < 0 || z + y != 0) /* not compliant - 逻辑运算符两边运算要加括号 */
{
flag = FALSE;
}
if ( flag && get_bool() ) /* not compliant - 设置206可不报错,否则报错 */
{
flag = FALSE;
}
}
2,存在空语句
if(1)
{
/*如果空语句是故意的,添加一个/**/*/
}
3.对有符号类型位操作
对有符号数进行位操作时非常不安全的行为。例如,与(&)或者或(|)操作符对于结果的执行时非常明确地,这就有可能导致标志位丢失,或者把数值换到了符号位当中。
void static_120(void)
{
SINT_32 b = 1;
b = b | 1; /* not compliant */
}
4,复杂表达式中使用VOLATILE变量
volatile变量的值可能在使用过程中而被改变(非控制改变)。这个标准可以把在表达式中使用相同volatile变量多于一次的表达式报告出来。因为返回的值有可能是各个阶段表达式的值,所以有可能是不一样的,这种情况是不安全的。安全的做法是在简单不可再优化表达式中只使用变量一次。如果需要在所有表达式的部分中使用同样的值,最好是把当前值保留在一个局部变量中,用局部变量来代表volatile变量,再用于表达式当中。
volatile UINT_32 v = 1U;
UINT_32 x, a;
x = v*v; /* this is unsafe, v could change*/
a = v;
x = a*a; /* this is safe, the value of v was captured */
5,有符号/无符号间无强制类型转换
不同类型之间的转换需要使用显式强制类型转换,以说明类型转换是人为的,不存在无意中丢失的信息(或已知晓会丢失)。默认类型转换是比较有代表性的定义操作,这种操作有可能导致未定义的行为发生。
void static_434(UINT_32 us1)
{
SINT_32 ss1 = us1; /* converting to signed may result in a loss of information */
/* ... */
}
6,默认转换为范围更窄整型
转换成一个更小范围的类型需要使用强制类型转换,以说明类型转换是人为的,不存在无意中丢失的信息(或已知晓会丢失)。默认类型转换是比较有代表性的定义操作,这种操作有可能导致未定义的行为发生。
static void static_446 ( void )
{
UINT_16 u16;
UINT_32 u32a,
u32b;
u16 = u32a + u32b; /* not compliant – 会默认从32位转换成16位 */
}
7,if,else需要加括号
8,枚举初始化
enum (x,y,z) /*GOOD (unless type 377 is set) – 未明确初始化*/
enum (x=1,y,z) /*GOOD – 只初始化第一个值*/
enum (x=2,y=3,z=4) /*GOOD – 初始化所有值*/
enum (x,y,z=1) /*BAD – 不允许只初始化部分*/
不规范案例
enum
{
a = 0x01,
b,
c=0xff,
}
9,必须要有形参
{
void fun(void)
}
10,函数返回局部结构体
一个函数不应该返回一个指向局部结构体对象的指针。在被调用函数的返回后,局部对象会存在于数据范围之外并且不再存在。
struct tag
{
UCHAR * uptr;
};
static struct tag SDA_077 (void)
{
UCHAR loc = 42;
struct tag rtag;
rtag.uptr = &loc;
return rtag; /* Not compliant */
}
11,指针相减地址并不指向数组
指向不同对象的指针不能直接相减,这样得出的地址指向的并不是数组,且有可能会导致无法定义的行为发生。
typedef signed int Sint_32;
void foo(void)
{
Sint_32 ss1[10];
Sint_32 ss2[10];
Sint_32 *ss1_ptr = &ss1[0];
Sint_32 *ss2_ptr = &ss2[0];
Sint_32 ss3 = ss1_ptr - ss2_ptr;
/* not compliant – 指向不同数组的指针不能直接相减*/
}
12,IF语句中没有ELSE分支
13,数组初始化 应该赋值为0,尽管bbs段默认赋值为0
14,FOR循环语句初始化过于复杂
For循环中的初始化表达式(即第一项)不应该存在执行语句,除了给循环参数赋一个简单值。
void static_270(void)
{
UINT_32 loop;
UINT_32 myVar = 0U;
const UINT_32 max = 10U;
for ( ++myVar, loop = 0U; loop < max; loop++ ) /* not compliant */
{
/* ... */
}
}
15,结构成员名称重用
struct I_var_a
{
INT_32 ip1;
INT_32 ip2;
} I_var_a;
struct I_var_b
{
INT_32 ip2; /* not compliant */
INT_32 ip3;
INT_32 ip4;
} I_var_b;
16,强制转换VOLATILE 值
尽量避免抛弃volatile条件,因为这有可能会导致编译器最优化有效执行时,在建立优化的时候出现意想不到的结果。
volatile UINT_32 *y1;
static void static_344 ( void )
{
UINT_32 *y2 = (UINT_32 *)y1;
/* not compliant - cast to ... a pointer to non-volatile int */
}
17,循环中不止一条break/goto
所有内部操作中都应该最多只有一条break语句来用于结束一个循环。如果代码是良好结构的,那是没有必要使用多于一个break语句的。
#include "c_standards.h"
#include <stdio.h>
const INT_32 max_num = 10;
void static_409( char arr[] )
{
INT_32 sub;
for (sub = 0; sub < max_num; sub++)
{
if (arr[sub] == '\0')
{
break;
}
(void) printf("%c", arr[sub]);
if (arr[sub] == 'z')
{
break; /* not compliant – 这个循环已经出现过一次break了*/
}
}
}
18, 指针运算不在数组上
在非数组的指针上进行算术运算被认为是非常不安全的做法(直接对地址进行操作),因为这样很难保证结果是在有效地址上的。
#include "c_standards.h"
static void static_567( UINT_32 * pp );
static void static_567( UINT_32 * pp )
{
UINT_32 * xx;
xx = pp +7; /* not compliant */
}
19,在循环体内改变循环计数
一个循环计数是在循环中用于反复计数的,不应该在循环体内被改变。改变循环计数变量会导致代码难以阅读和维护。
static void SDA_055( UINT_32 max_count )
{
UINT_32 loop_counter = 0U;
for (loop_counter = 0U; loop_counter < max_count; loop_counter++)
{
if (loop_counter == 7U)
{
loop_counter++; /* not compliant */
}
else
{
/* do nothing */
}
}
}