extern 定义_功能安全实践 | 定义编程Style和命名规则

点击上方?“汽车知识共享空间”关注订阅号,设为星标⭐获取更多实时内容更新。。。   

    功能安全标准ISO26262-6 Table1的1g中推荐ASIL B及高于ASIL B等级的代码需要use of style guides(使用风格指南)所有涉及功能安全的代码都需要使用命名规则(1.h Use of naming conventions).什么是风格指南?为什么会有这样的要求,笔者初次接触这个要求时也十分茫然,我写的代码只要过了单元测试不就可以了么?为什么一定要定义风格呢?

首先咱们一起来看看为什么这个问题。

      刚学编程的时候,老师通常会说养成良好的编程习惯,比如,变量的名字要有意义不要单纯的用x,y,a,b,c这样的字母来对形参命名。笔者工作至今,老师当年有一个问题今天回忆起来依然记忆犹新。你今天写了一段代码,过三个月后你回来再看这段代码,你需要花多长时间能读懂它?如果看代码的人不是你,又需要花多长时间可以看懂这段代码?

     所谓编程风格(Programming Style)可以理解为程序员在写代码的时候需要使用的一系列规则或者或者指南,这些规则或者指南的目的是帮助自己或者他人来准确、快速的理解代码需要表达的内容。好的编程风格指南可以增加程序的可读性,消除对代码理解上的歧异,无论是是对单元测试还是代码评审验证甚至后期的维护升级都可以带来便利。

    另一方面,我们参考文章《汽车电子读书笔记-专业术语解析03-失误、偏差与失效》从fault、error、failure三者之间的关系出发,好的编程风格可以从源头上降低fallt发生的可能性。

    正是因为有上面介绍的这些优点,可以明显改善安全相关软件的代码质量。所以,26262才推荐我们来使用编程风格指南。同理,命名规则的好处也是如此。虽然,功能安全标准推荐ASILB及以上等级系统使用编程风格指南,但是,从开发以及使用的角度出发,尤其是比较复杂的程序,无论你是否涉及安全,笔者建议都应该使用编程风格指南(Programming Style Guideline)。   

     说了这么多好处,接下来让我们来一起看看如何定义好的编程风格指南

     笔者是从事C语言开发相关工作的,就以C语言为例进行说明,此处需要说明一点。由于不同的编程语言在语法规则上会有些许的不同,所以很多规则不一定具有广泛的适用性。需要各位读者结合自己的应用情况进行调整

      1.文件的组织与引用

对于复杂系统,尤其是那些以万行为单位来计算的软件,不可能只有一个模块,也不可能只有一个.c文件。如果你的系统需要分成若干个.c文件的话,必然会涉及文件的引用问题。我们都知道C语言属于编译型语言,C语言的原始代码在编译转化的过程中是以.C为基础进行的即以单个.C文件为单位进行编译。C语言的代码在编译之前需要进行预处理来整合头文件也就是平时我们看到的.h。笔者这里推荐的好的编程风格就与预处理相关。

    1.1  所有与本模块相关的自定义类型typedef都放在一个头文件中。比如模块A的源文件是Module_A.c那么,所有与Module_A模块相关的typedef都放在Module_A.h这个文件中。为什么要这么做,主要是,如果所有与本模块相关的typedef有的出现在源文件.c中,有的出现在.h头文件中的话,会降低程序的可读性增加更改的难度。而且,如果,涉及到跨模块的引用怎么办?总不大可能直接引用.c吧。

    1.2 所有的宏定义必须放在头文件中完成,此处最好规定好命名规则比如,所有涉及宏的内容的头文件因为常常与配置相关,可以规定它的名字中包含cfg(configration的缩写)来与其他的头文件进行区分。

     1.3 所有的全局变量都必须加static前缀,当然也可以在编程风格中规定,所有extern的全局变量只能在.c中定义一次,并且只能在.h文件中进行声明。但是,按照功能安全的标准我们真的不希望出现extern的变量(extern 的const类型没有问题哈,这个是常量不涉及意外更改),具体怎么处理可以参考文章《功能安全实践 | 如何安全使用全局变量》。

     1.4 所有的static函数都必须在源文件的头部声明函数原型。为什么会有这条规定,是因为万一函数在源文件中的顺序调整了,你要保证存在调用关系的函数不会报错。

     1.5 所有的全局函数都只能在头文件中定义函数原型即用extern进行声明,不允许在.c中进行extern声明。为什么要做这条规定,是因为调用的时候最佳的方式是调头文件。

     1.6 每行只允许存在一个变量定义或者声明

     2 缩进的使用:

我们先来看一段没有缩进定义的代码;

#include <stdio.h>

int main(void) {

int seg[10] = {6,2,5,5,4,5,6,3,7,6};

int d1, d2, d3, d4, m=0, td, ts;

for (d1=0; d1<2; d1++)

for (d2=0; d2<10; d2++)

for (d3=0; d3<6; d3++)

for (d4=0; d4<10; d4++)

if ((!((d1==0)&&(d2==0))) && (!((d1==1)&&(d2>2)))) {

    if (d1==0) {

ts = seg[d2] + seg[d3] + seg[d4];

td = d2 + d3 + d4;

if (ts == td) { m++;

printf(" %1d:%1d%1d\n",d2,d3,d4); }

} else {

ts = seg[d1] + seg[d2] + seg[d3] + seg[d4];

td = d1 + d2 + d3 + d4;

if (ts == td) { m++;

    printf("%1d%1d:%1d%1d\n",d1,d2,d3,d4); }

} }

return 0; }

无论你是否学过C语言看到这段代码,大部分人的第一印象都会是,这是什么东西3c44bdca55abcc04abae0f96448c5746.png

让我们增加一下缩进,再来看一下:

#include <stdio.h>

int main(void) 

{

     int seg[10] = {6,2,5,5,4,5,6,3,7,6};

     int d1, d2, d3, d4, m=0, td, ts;

     for (d1=0; d1<2; d1++)

         for (d2=0; d2<10; d2++)

             for (d3=0; d3<6; d3++)

                   for (d4=0; d4<10; d4++)

                          if (

                                       (           !(   

                                                       (d1==0) && (d2==0)

                                                     )

                                           ) 

                                           && 

                                           (         !(

                                                             (d1==1) && (d2>2)

                                                       )

                                           )

                                      ) 

                            {

                                     if (d1==0)

                                         {

                                                ts = seg[d2] + seg[d3] + seg[d4];

                                                td = d2 + d3 + d4;

                                               if (ts == td) 

                                                      { 

                                                              m++;

                                                              printf(" %1d:%1d%1d\n",d2,d3,d4); 

                                                          }

                                        } 

                                     else

                                          {

                                                   ts = seg[d1] + seg[d2] + seg[d3] + seg[d4];

                                                   td = d1 + d2 + d3 + d4;

                                                   if (ts == td) 

                                                            { 

                                                                      m++;

                                                                     printf("%1d%1d:%1d%1d\n",d1,d2,d3,d4);

                                                              }

                                           } 

                           }

return 0; 

}

同样的一段代码,层次分开后的可读性明显改善。

2.1每个指令块至少缩进2个空格(有些推荐4个空格)。这样的话你的代码层次会非常清楚。

2.2 涉及到多层运算的语句需要展开,并且保证相同层次的括号对齐。为什么要增加这条约束,主要是因为,比如例子中的第一个if,如果你是基于代码的开发,不小心漏掉一个括号。如果编译阶段报错的话,没有清晰的层次,你很难知道自己的编码在什么地方出了错。

2.3 代码块中大括号"{"或者“}”需要单独保持一行,并且对齐。这项要求的原因与2.2一样。

3.空格与空行

因为示例代码太占空间了,咱们接下来就直接写结论了。

3.1 变量与函数之间的定义需要留空白行

3.2 函数与函数之间需要留空白行。

3.3  二目运算符两边需要留空格

缩进案例中使用的示例代码,是明显不符合MISRA C 2012要求的,无论是变量的定义还是注释(代码根本就没有注释289e2ae67a397d8ba7f6bf3749680b43.png,要求更加严格的代码,会要求HIS指标中注释密度,这个留在后续文章中给大家讲)。对于注释,本文在注释方面的解释还不够完善,比如可以根据您所在公司的现状,定义标准的注释头文件,同时还需要结合代码写作习惯规定好注释的具体位置(比如,注释只允许出现被注释代码的上方或者右侧等)。MISRA C中也有很多细节的要求比如不可以用 //。另外,对于宏也是,比如,MISRA C 2012不建议用#if define,头文件必须用宏来限制编译范围等。这些属于MISRA C中有明确要求的本文就不再赘述。如果读者感兴趣,可以留言,笔者后续可以再整理一下关于MISRA C中提到的C语言约束。

4命名规则。

我们接下来看看命名规则,常用的命名规则主要有以下两种:

a.骆驼规则(camel naming rule)  这种命名方法一般是第一个单词的首字母小写,后续单词的每一个首字母大写。就像骆驼的驼峰一样。一般变量名称,需要使用骆驼规则进行命名。

b. Pascal命名规则(Pascal naming rule),这种命名规则是所有单词的首字母都使用大写,一般用来给函数命名。

重点来了,其实你可以两种规则都不用,也可以只选择一种使用。如果你用的是autosar,可以直接使用autosar命名规则。如果不是autosar,那么笔者建议可以采用如下命名规则:

模块名称_功能名称_子功能名称

其中模块名称可以采用首字母缩写的形式,比如Electronic stability control 可以直接缩写成ESC,后面的功能名称和子功能名称,可以视你选择的C语言版本已经目标芯片的位宽来进行具体的长度限制或者缩写分类

上面这些意见,结合一定的伪代码说明与MISRA C2012的相关规定,就可以设计出符合功能安全标准,同时属于您自己公司的C语言编程风格指南。当然还有更多好的风格建议期待您的补充,如果,您有更多的关于C语言编程风格的建议,非常欢迎您在文章下方留言,供大家一起分享讨论。

d319db37d05005598d3e55d624607c23.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值