编码规则可维护性.docx

上传人:b****8 文档编号:9685196 上传时间:2023-02-05 格式:DOCX 页数:76 大小:55.34KB
下载 相关 举报
编码规则可维护性.docx_第1页
第1页 / 共76页
编码规则可维护性.docx_第2页
第2页 / 共76页
编码规则可维护性.docx_第3页
第3页 / 共76页
编码规则可维护性.docx_第4页
第4页 / 共76页
编码规则可维护性.docx_第5页
第5页 / 共76页
点击查看更多>>
下载资源
资源描述

编码规则可维护性.docx

《编码规则可维护性.docx》由会员分享,可在线阅读,更多相关《编码规则可维护性.docx(76页珍藏版)》请在冰豆网上搜索。

编码规则可维护性.docx

编码规则可维护性

第2章维护性

2006/11/10V1.00

大多嵌入式软件开发中,都会在制作完成的软件上进行维护作业。

 维护的原因各种各样,例如:

・发布的软件中发现Bug,需要修改。

・对应产品的市场要求,以既存软件为基础,追加新的功能。

 等等。

 像这样,在制作好的软件上加工,要尽量避免错误,有效的进行。

 系统界管这叫维护性。

 在此,整理了维护、提高嵌入式软件源代码维护性的一些惯用方法。

1维护性1・・・意识到其他人也会看你的代码。

2维护性2・・・使用不会改错得方法。

3维护性3・・・把程序尽量简单化。

4维护性4・・・统一编码方法。

5维护性5・・・使用便于测试的编码方法。

6维护性6・・・Uniden(株)Know-how集。

维护性1

意识到其他人也会看你的代码。

在制作源代码时考虑到,它会被制作者以外的技术者再利用或维护。

因此,源代码要使用容易理解的表现方式。

「维护性1」有以下12个惯用做法。

维护性1.1 不保留不使用的代码。

维护性1.2 不使用麻烦,杂乱的写法。

维护性1.3 不使用特殊的写法。

维护性1.4 演算的优先顺序明确易懂。

维护性1.5 不省略取得函数地址的演算、比较演算。

维护性1.6 一个领域用于一个目的。

维护性1.7 不重复使用名字。

维护性1.8 不使用容易理解错的语言规格。

维护性1.9 在特殊的方法中写明意图。

维护性1.10 不掩埋MagicNumber。

维护性1.11 明示领域属性。

维护性1.12 不编译的语句也要正确记述。

维护性1.1 不遗留不使用的代码。

M1.1.1 不声明(定义)没有使用的函数、变量、参数、标签。

参考规则 无

相关规则 M1.9.1M4.7.2

M1.1.2 不应该把代码的一部分“Commentout”。

参考规则 MISRA-C2.4

相关规则 M1.2.1M4.7.2

<正确例> 

#if0/*因为~、无効化*/

a++;

#endif

<不正确例>

・・・・・・・

/*a++;*/

・・・・・・・

}

如果需要把代码部分无効化,建议不要用Commentout,而是用#if0圈住。

或者确定一个无効化代码的明确规则也行。

但是,留下无効代码会导致代码不好读,还是应该避免的。

note

在调试时,会Commentout一部分代码,但是调试结束后不要忘了解除Comment,否则可能会发生Bug。

如果限制了Commentout代码,就可以在早期发现这些Bug。

维护性1.2 不使用麻烦,杂乱的写法。

M1.2.1 用于相同目的的相同类型的自动变量,可以用1个声明语句进行多次声明,但是不可以混合初始化的变量和不初始化的变量。

参考规则 无

相关规则 M1.6.1

<正确例> 

intj,k;

intl=0;

int*p;

intq;

<不正确例>

intj,k,l=0;/*混有初始化的内容*/

int*p,q;/*混有不同类型的变量*/

如果声明了int*p;,那么类型就是int*、如果声明了int*p,q;,q的类型不是int*、而是被解释为int。

 note

   写常量时,如果不使用接尾语的话,整数常量为int型、浮动小数点常量为double型。

但是,整常量中如果有int不能表现的值,那么这个值将会变成能表现它的类型。

因此,0x8000在int为16bit时为unsignedint,但在int为32bit时变成signedint。

如果想把它作为unsigned使用的话,把”U”写为接尾语。

另外,在浮动小数点的float型和double型演算速度不同的TargetSystem中,进行float型的变量和浮动小数点的演算时,如果浮动小数点常量中没有”F”,这个演算就会变成”double”型的演算,这一点需要注意。

要在浮动小数点常量上多下些功夫,使其一看就能知道是浮动小数点常量,比如在小数点左右最少要写一个数字等等。

   特别是在演算精度、演算速度很重要的程序中,必须要充分理解实际是使用的那种类型的演算。

(不要Cut&Try。

整数常量的类型

接尾语u/U:

unsignedint,unsignedlong

接尾语l/L:

long,unsignedlong

接尾语u/Uとl/Lの両方:

unsignedlong

浮动少数点常量的类型

接尾语f/F:

float

接尾语l/L:

longdouble

维护性1.3 不使用特殊的方法。

M1.3.1 switch(式)的表达式中,不用求真假结果的表达式。

参考规则 无

相关规则 无

<正确例> 

if(val1==0){

val2=0;

}else{

val2=1

}

<不正确例>

switch(val1==0){

case0:

 val2=1;

 break;

default:

 val2=0;

 break;

}

如果在Switch语句中使用求真假结果的表达式,分歧数就会变成2个、不需要在多分歧命令的switch语句中使用。

switch语句和if语句相比,容易出现default节的错误记载、break语句的遗漏等错误,所以如果不是3分歧以上,建议使用if语句。

M1.3.3 switch(式)的表达式中,不用求真假结果的表达式。

参考规则 MISRA-C8.2IndianHill8

相关规则 M4.5.1

<正确例> 

externintglobal;

intfunc(void){

・・・・・・・

}

<不正确例>

externglobal;

func(void){

・・・・・・・

}

在函数、变量的定义、声明中没有数据类型时,被解释为int型,明确记述数据型会看起来更方便。

 

维护性1.4 演算的优先顺序明确易懂

M1.4.1 &&、||演算的右式和左式是单纯的变量或()括起来的公式。

但是,&&演算连续结合时,或||演算连续结合时、不需要用()括住&&式或||式。

参考规则 无

相关规则 R2.3.2M1.5.2

<正确例> 

if((x>0)&&(x<10))

if((!

x)||y)

if((flag_tb[i])&&status)

if((x!

=1)&&(x!

=4)&&(x!

=10))

<不正确例>

if(x>0&&x<10)

if(!

x||y)

if(flag_tb[i]&&status)

if(x!

=1&&x!

=4&&x!

=10)

只有单纯变量的表达式和用()括住的表达式叫做一次式。

一次式中,包括常量或文字列参数。

&&或||的各项有一次式的规则。

在有Operator的表达式中用()括住的目的是,&&或||演算的各项演算会变得很醒目,可以提高可读性。

note

在软件制造工程中,有各种技能的工程师进行作业。

特别是技能不好的工程师,可能对C语言规则的理解度不是很够。

所以,下功夫制作简单易懂的代码,让这些工程师也能正确理解代码是很重要的。

C语言中,Operator的优先顺序如下。

 

Operator的优先顺序

优先程度

Operator

结合规则

15

()  []   -> ・

 

 

 

 

 

 

 

左→右

 

14

Sizeof(型) &   -+  --  ++  ~   !

13

*   /   %

12

+   -

11

<<  >> 

10

<   <=   >   >=

9

==   !

=

8

&

7

^

6

|

5

&&

4

||

3

?

   :

2

>>=  <<=  ^=  &=  %=  /=  *=  -=  +=  =

1

 

这个标的纵轴表示优先顺序的等级(数字越大,优先度越高)。

结合规则表示的是,优先顺序同等级时的演算顺序。

M1.4.2 为了明确演算的优先顺序,规定使用括号。

参考规则 无

相关规则 M1.5.1 制作规则。

<正确例> 

a=(b<<1)+c;

a=b<<(1+c);

<不正确例>

a=b<<1+c;/*优先顺序有可能错误*/

C语言的Operator优先顺序因为很容易被看错,制定如下的规则比较好。

表达式中包括优先顺序不同的多个2项Operator时,为了明示优先顺序,使用括号。

但是,四则演算相关的可以省略括号。

note

 Operator作用的变量叫做Operand。

取1个Operand的Operator叫「单项Operator」(UnaryOperator),取2个Operand的Operator叫「二项Operator」(BinaryOperator),取3个Operand的Operator叫「三项Operator」。

SizeofOperator为单项Operator,单纯代入Operator为二项Operator,?

Operator为3项Operator。

单项Operator :

 反转Operator!

间接指定(指针)*,地址Operator&,CastOperator(type), sizeofOperator,Increment++Decrement,理论(Loop)Operator&&||等

二项Operator :

 算术Operator*/%+-,BitOperator<<>>&|^~,代入Operator=,+=,-=,*=,/=,关系(比较)Operator<=,<,>=,>,==,!

=等

三项Operator :

 ,`式1?

式2:

式3;'

维护性1.5 不省略取得函数地址的演算、比较演算。

M1.5.1 必须指定、使用函数标识符(函数名)前面是用&、还是括号的形式参数List(空的也行)。

参考规则 MISRA-C16.9

相关规则 无

<正确例> 

voidfunc(void);

void(*fp)(void)=&func;

if(func()){

<不正确例>

voidfunc(void);

void(*fp)(void)=func;/*NG:

没有&*/

if(func){/*NG*不是函数调用,而是取得地址。

有时可能会写成调用没有参数的函数*/

C语言中、如果只取得函数名就不是函数调用,而是取得函数地址。

也就是说,取得函数地址不需要加&。

但是,如果没有&,有时会弄错函数调用(Ada等在没有参数的子程序调用中,只写了名字时等)。

在取函数地址时,通过遵守“加&”的规则,可以检查出没有加&、也没有()的函数名、就能找到错误(失误)。

 note

函数型的语法如下。

∙除sizeofOperator和地址Operator以外的表达式中,返回T型的函数(functionreturningtypeT),会变成指向返回T型函数的指针。

这个语法和队列一样,式特别准备的。

(不使用地址Operator也能取得地址的只有队列和函数。

)例如,

doublef(char,int);

时,函数指示子(式)f变成函数f的地址。

   可以接受函数地址的指针是「指向函数的指针」。

例如,在接收上述函数f的地址时,要变成声明了

double(*pf)();

的指针pf。

这就是指向返回double的函数的指针。

维护性1.6 1个领域只用于一个目的

M1.6.1 每个目的都准备一个变量。

参考规则 MISRA-C18.3

相关规则 M1.2.1

<正确例> 

/*用于跟Counter变量替换的作业变量为其他变量*/

for(1=0;j

data[j]=j;

}

if(min>max){

wk=max;

max=min;

min=wk;

}

<不正确例>

/*用于跟Counter变量替换的作业变量为相同变量*/

for(1=0;j

data[j]=j;

}

if(min>max){

j=max;

max=min;

min=j;

}

再次利用变量会降低可读性,在修改时会增加修改错误的危险性。

 note

   为了减少堆帐使用量,有时会再次使用自由变量。

最近的编译器中就算准备各自的自由变量也不能最适化,所以没多大意义。

另外,再次使用自由变量会导致变量的存在期间长,所以堆帐使用量也可能会増加。

M1.6.2 使用共用体时,書き込んだMemberで参照する。

参考规则 无

相关规则 M1.2.3

<正确例> 

/*typeがINT→i_var、CHAR→c_var[4]*/

structstag{

int_type;

unionutag{

charc_var[4];

inti_var;

}u_var;

}s_var;

・・・・・・・

inti;

・・・・・・・

if(s_var.type==INT){

s_var.u_var.i_var=1;

}

・・・・・・・

i=s_var.u_var.i_var;

<不正确例>

/*typeがINT→i_var、CHAR→c_var[4]*/

structstag{

int_type;

unionutag{

charc_var[4];

inti_var;

}u_var;

}s_var;

・・・・・・・

inti;

・・・・・・・

if(s_var.type==INT){

s_var.u_var.c_var[0]=0;

s_var.u_var.c_var[1]=0;

s_var.u_var.c_var[2]=0;

s_var.u_var.c_var[3]=1;

}

・・・・・・・

i=s_var.u_var.i_var;

共用体可以在不同大小的领域中声明一个领域,但Member间的Bit的重叠方式依赖于处理系统,所以不一定会变成想要的动作。

使用时需要注意。

  note

MISRA-C18.4中禁止使用共用体,因为依赖于处理系统的处理很多,所以尽量不用的好。

维护性1.7 不再次使用同一个名字。

M1.7.1 名字的统一性遵从以下规则。

1.外部Scope的标识符是隐蔽的,所以内部Scope的标识符中,不可以使用跟外部Scope一样的名字。

【MISRA5.2】

     2.typedef名必须是固有的标识符。

【MISRA5.3】

     3.Tab名必须是固有的标识符。

【MISRA5.4】

     4.持有静的记忆域期间的Object或函数标识符不应该再次使用。

【MISRA5.5】

     5.除了构造体和共用体的Member名,不可以把一个NameSpace的标识符用于其他的NameSpace标识符处。

【MISRA5.6】

参考规则 MISRA-C5.25.35.45.55.6

相关规则 M4.3.1

<正确例> 

intvar1;

voidfunc(intarg1){

intvar2;

var2=arg1;

{

intvar3;

var3=var2;

}

}

<不正确例>

intvar1;

voidfunc(intarg1){

intvar1;/*名字和函数外侧的变量名一样*/

var1=arg1;

{

intvar1; /* 名字和外侧的有効范围中的变量名一样 */

  …

var1=0; /* 不知道想代入哪个var1 */

除了自动变量等有効范围被限制时,名字在程序中要尽量保持统一,让程序易读。

C语言中,名字除了file、Block等限制的有効范围,还有另外的4个名字空间。

1.标签 2.Tab 3.构造体・共用体的Member 4.其他标识符

   ※宏没有名字空间

除了自动变量等有効范围被限制时,名字在程序中要尽量保持统一,让程序易读。

在语言规格上,如果名字空间不同,那么用相同的名字也行。

但这个规则中是限制的,目的是为了制作易读易懂的程序。

 note

用于变量、函数命名的规则说明。

1.变量、函数的名字中能使用的文字有英文(大・小)、数字、UnderScore(_)等共计63个文字。

这些文字可以自由组合形成名字。

但是,最初的文字一定要是英文或UnderScore。

2.名字取多长都行,但通常有効的文字数只到第8个文字。

另外,名字不可以只是一个UnderScore。

3.C语言中,明确区分了英语大写和小写。

通常,C语言中是用小写来写程序。

大写用于表示特殊意义。

4.C语言中,和其它的编程语言一样,有些名字是固定使用的。

这些叫做预约语(关键字)。

变量名、函数名中不能使用跟预约语相同的名字。

通常、预约语有28个。

另外,根据C编译器的不同,预约语也多少有些不一样,请在编译器的说明书中确认。

 

C语言的预约语

 

预约语

意义

 

 

 

 

 

数据型

记忆class

 

auto

自动变量的声明

char

文字型变量的声明

double

倍精度浮动小数点型变量的声明

extern

外部变量的声明

float

浮动小数点型变量的声明

int

整数型的声明

long

倍精度整数型的声明

register

寄存器变量的声明

short

短い整数型的声明

static

静的变量的声明

struct

构造体的声明

typedef

型的定义

union

共用体的声明

unsigned

符号无整数的声明

 

 

 

控制

 

 

break

从Loop跳出

case

switch~case的定义

continue

返回以下的重复内容

default

switch~default的定义

do

doLoop

else

if~else

for

forLoop

goto

无条件分歧

if

条件判定

return

从函数返回

switch

多条件分歧

while

whileLoop

其他

entry

无意义

sizeof

数据型的长度

M1.7.2 标准库的函数名、变量名及宏名不能再定义・再利用,而且不能解除定义。

参考规则 MISRA-C20.1

相关规则 M1.8.2

<正确例> 

#include

void*my_memcpy(void*arg1,constvoid*arg2,size_t_size){

・・・・・・・

}

<不正确例>

#undefNULL

#defineNULL((void*)0)

#include

void*my_memcpy(void*arg1,constvoid*arg2,size_t_size){

・・・・・・・

}

在标准库中,独自定义已定义的函数名、变量名、宏名,会降低程序的可读性。

  note

 

M1.7.3 不能再定义以下划线开视的名字(变量)。

参考规则 无

相关规则 M1.8.2

<正确例> 

<不正确例>

int_Max1;/*被预约*/

int__max2;/*被预约*/

int_max3;/*被预约*/

structS{

int_mem1;/*没有被预约,但不使用*/

}

C语言规格中,以下名字已被预约。

(1)下划线后是大写英文,或2个下划线开头的名字,不管如何使用都是已被预约的。

      例:

 _Abc,__abc

(2)1个下划线开头的所有名字

      这个名字对应有file的有効范围的变量、函数的名字和Tab名,已被预约。

      再次定义已被预约的名字,会导致无法保证编译器的动作。

      一个下划线开头,后面是小写文字的名字,在file有効范围以外的部分中没有被预约。

但为了使规则易记,将其规定为,不使用下划线开头的所有名字。

  note不明白已被预约的意思。

(誰?

维护性1.8 不使用容易理解错的语言规格。

M1.8.1 理论Operator&&或||右侧的Operand中不能有副作用。

参考规则 MISRA-C12.4

相关规则 R3.6.1R3.6.2

<正确例> 

a=*p;

p++;

/*p不依赖于p指向的内容,已经countup*/

if(((MIN

・・・・・・・

}

<不正确例>

/*p指向的内容小于MIN时和大于MIN时,p是否Countup的结果不一样。

(难解)*/

if(((MIN

・・・・・・・

{

&&、||Operator的右式是否执行依赖于左式的条件结果。

如果右式中是Increment等有副作用的表达式、那么左式条件不同时,又可能会Increment也有可能不会,因为这样非常难理解,所以,&&、||Operator的右式中不要采用有副作用的表达式。

note

 理论Operator和关系Operator一样,在真的时候int型返回1,假的时候返回0。

■理论Operator(LogicalOperators)

x&&y 

理论ANDOperator

(LogicalANDOperator)

理论积(AND,∧):

一方为0时返回0,两方都为0以外的话,返回1。

x||y

理论OROperator

(LogicalOROperator)

理论和(OR,∨):

一方不为0时返回1,两方都为0时返回0。

Operand可以使用所有的Sculler型。

理论积中,第1Operand为0的话就不评估第2Operand了。

理论和中如果第1Operand不为0就不评估第2Operand。

M1.8.2C宏只能展开为用大括号括住的初始化子、常量、括号括住的表达式、型修饰子、记忆域Class指定子、do-while-zero构造。

参考规则 MISRA-C19.4

相关规则 M1.7.2

<正确例> 

#defineSTART0x0410

#defineSTOP0x0401

<不正确例>

#defineB

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 总结汇报 > 学习总结

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1