精华内容
下载资源
问答
  • 嵌入式 软件开发 编程 规范 涉及嵌入式软件开发经常需要注意的问题!涉及嵌入式软件开发经常需要注意的问题!涉及嵌入式软件开发经常需要注意的问题!
  • 嵌入式软件开发之编程规范(个人)规范目的变量命名规则函数命名规则合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、...

    规范目的

    描述嵌入式软件开发流程中,代码编写及命名规则,有利于项目开发和维护,增强可读性、规范性、复用性。

    变量命名规则

    变量类型 前缀 举例 重定义类型
    char c char cLength; int8_t
    short s short sLength; int16_t
    int i int iLength;
    long l long lLength; int32_t
    unsigned char uc unsigned char ucLength; uint8_t
    unsigned short us unsigned short usLength; uint16_t
    unsigned int ui unsigned int uiLength;
    unsigned long ul unsigned long ulLength; uint32_t
    bool b 或 is bool bLength;
    float f float fLength;
    double float d double float dLength;
    枚举 e enum eLENGTH;
    结构体 str INFO strLength;
    指针 p char* pLength;
    结构体指针 pstr INFO* pstrLength;
    结构体数组 astr INFO astrLength[];
    数组 a char aLength[];
    作用域 前缀 举例
    局部变量 int8_t length;
    静态变量 s_ int8_t s_cLength;
    全局变量 g_ int8_t g_cLength;
    静态全局变量 sg_ int8_t sg_cLength;

    函数命名规则

    撤销:Ctrl/Command + Z

    排版规则

    缩进
    缩进使用制表符,一个制表符等于4个空格。
    注释
    Text-to-HTML conversion tool
    空行
    Text-to-HTML conversion tool
    Markdown
    Text-to-HTML conversion tool
    Markdown
    Text-to-HTML conversion tool
    展开全文
  • 嵌入式软件开发编程规范及原则!

    千次阅读 2018-09-17 11:30:00
    写在前面Ⅰ不知道大家有没有这样的感受:看到不规范(杂乱差)的代码,瞬间就没有看下去的欲望了。 相信大家看到标题都应该能明白编程的规范及原则对于每一个软件开发的工程师来说是...
        

    640?wx_fmt=jpeg


    写在前面

    不知道大家有没有这样的感受:看到不规范(杂乱差)的代码,瞬间就没有看下去的欲望了。

     

    相信大家看到标题都应该能明白编程的规范及原则对于每一个软件开发的工程师来说是多么重要。

     

    初学者编写测试程序、小的模块程序也许不能感受它的重要性;但有经验及大型项目开发的人就知道程序的规范性对他们来说是有多么的重要。


    关于编程规范及原则

    编程规范也就是编写出简洁、可维护、可靠、可测试、高效、可移植的代码,提高产品代码的质量。

    本文针对嵌入式,主要结合C语言编程的规范给大家讲述。

     

    1.头文件

    对于C语言来说,头文件的设计体现了大部分的系统设计,不合理的头文件布局是编译时间过长的原因

     

    有很多人将工程中所有的头文件包含在一个include.h文件中,然后在每一个.c源代码文件中包含include.h头文件,这样做可以让代码看上去简洁,但实际忽视了编译效率问题,而且代码的可移植性也不好。

     

    原则

    A.头文件中适合放置接口的声明,不适合放置实现;

    B.头文件应当职责单一;

    C.头文件应向稳定的方向包含。

     

    规则:

    A.每一个.c文件应有一个同名.h文件,用于声明需要对外公开的接口;

    B.禁止头文件循环依赖;

    C..c/.h文件禁止包含用不到的头文件;

    D.头文件应当自包含;

    E.总是编写内部#include保护符( #define 保护);

    F.禁止在头文件中定义变量;

    G.只能通过包含头文件的方式使用其他.c提供的接口,禁止在.c中通过extern的方式使用外部函数接口、变量;

    H.禁止在extern "C"中包含头文件。

     

    建议:

    A.一个模块通常包含多个.c文件,建议放在同一个目录下,目录名即为模块名。为方便外部使用者,建议每一个模块提供一个.h,文件名为目录名;

    B.如果一个模块包含多个子模块,则建议每一个子模块提供一个对外的.h,文件名为子模块名(降低接口使用者的编写难度);

    C.头文件不要使用非习惯用法的扩展名,如.inc;

    D.同一产品统一包含头文件排列方式。

     

    2.函数

    函数设计的要点:编写整洁的函数,同时把代码有效组织起来

    函数整洁的要求:代码简单直接、不隐藏设计者的意图、用干净利落的抽象和直截了当的控制语句将函数有机组织起来。

     

    原则:

    A.一个函数仅完成一件功能;

    B.重复代码应该尽可能提炼成函数.

     

    规则:

    A.避免函数过长,新增函数不超过100行(非空非注释行);

    B.避免函数的代码块嵌套过深,新增函数的代码块嵌套不超过4;

    C.可重入函数应避免使用共享变量;若需要使用,则应通过互斥手段(关中断、信号量)对其加以保护;

    D.对参数的合法性检查,由调用者负责还是由接口函数负责,应在项目组/模块内应统一规定;

    E.对函数的错误返回码要全面处理;

    F.设计高扇入,合理扇出(小于7)的函数;

    G.废弃代码(没有被调用的函数和变量)要及时清除。

     

    建议:

    A.函数不变参数使用const;

    B.函数应避免使用全局变量、静态局部变量和I/O操作,不可避免的地方应集中使用;

    C.检查函数所有非参数输入的有效性,如数据文件、公共变量等;

    D.函数的参数个数不超过5;

    E.除打印类函数外,不要使用可变长参函数;

    F.在源文件范围内声明和定义的所有函数,除非外部可见,否则应该增加static关键字。

     

    3.标识符命名与定义

    程序命名是一个关键,如果命名不规范,自己写的代码,时间长了恐怕连自己都不知道是什么意思了。

     

    3.1通用命名规则

    常见命名风格:

    A.用下划线_‟分割,如text_mutex;

    B.大小写字母混用,如ReadRFCText

     

    规则:

    A.标识符的命名要清晰、明了,有明确含义,同时使用完整的单词或大家基本可以理解的缩写,避免使人产生误解;

    B.除了常见的通用缩写以外,不使用单词缩写,不得使用汉语拼音;

    C.产品/项目组内部应保持统一的命名风格.

     

    建议:

    A.用正确的反义词组命名具有互斥意义的变量或相反动作的函数等;

    B.尽量避免名字中出现数字编号,除非逻辑上的确需要编号;

    C.标识符前不应添加模块、项目、产品、部门的名称作为前缀;

    D.平台/驱动等适配代码的标识符命名风格保持和平台/驱动一致;

    E.重构/修改部分代码时,应保持和原有代码的命名风格一致。

     

    3.2 文件命名规则

    因为不同系统对文件名大小写处理会不同,建议文件命名统一采用小写字符。

     

    3.3 变量命名规则

    首先,全局变量十分危险,通过前缀使得全局变量更加醒目, 促使开发人员对这些变量的使用更加小心。

    其次,从根本上说,应当尽量不使用全局变量,增加g_和s_前缀,会使得全局变量的名字显得很丑陋,从而促使开发人员尽量少使用全局变量。

     

    规则:

    A.全局变量增加g_”前缀,静态变量增加“s_”前缀;

    B.禁止使用单字节命名变量,但允许定义i、 j、 k作为局部循环变量;

    C.使用名词或者形容词+名词方式命名变量。

     

    3.4 函数命名规则

    A.函数命名应以函数要执行的动作命名,一般采用动词或者动词+名词的结构;

    B.函数指针除了前缀,其他按照函数的命名规则命名。

     

    3.5 宏的命名规则

    A.对于数值或者字符串等等常量的定义,建议采用全大写字母,单词之间加下划线_‟的方式命名(枚举同样建议使用此方式定义);

    B.除了头文件或编译开关等特殊标识定义,宏定义不能使用下划线_‟开头和结尾。

     

    4.变量

    原则:

    A.一个变量只有一个功能,不能把一个变量用作多种用途;

    B.结构功能单一;不要设计面面俱到的数据结构;

    C.不用或者少用全局变量。

     

    规则:

    A.防止局部变量与全局变量同名;

    B.通讯过程中使用的结构,必须注意字节序;

    C.严禁使用未经初始化的变量作为右值;

     

    建议:

    A.构造仅有一个模块或函数可以修改、创建,而其余有关模块或函数只访问的全局变量,防止多个不同模块或函数都可以修改、创建同一全局变量的现象;

    B.使用面向接口编程思想,通过API访问数据:如果本模块的数据需要对外部模块开放,应提供接口函数来设置、获取,同时注意全局数据的访问互斥;

    C.在首次使用前初始化变量,初始化的地方离使用的地方越近越好;

    D.明确全局变量的初始化顺序,避免跨模块的初始化依赖;

    E.尽量减少没有必要的数据类型默认转换与强制转换。

     

    5.宏、常量

    因为宏只是简单的代码替换,不会像函数一样先将参数计算后,再传递。

     

    规则:

    A.用宏定义表达式时,要使用完备的括号;

    不规范:#define RECTANGLE_AREA(a, b) a * b

    规范:#define RECTANGLE_AREA(a, b) ((a) * (b))

     

    B.将宏所定义的多条表达式放在大括号中;

    C.使用宏时,不允许参数发生变化;

    #define SQUARE(a) ((a) * (a))

    int a = 5;

    int b;

    不规范:

    b = SQUARE(a++);

     

    规范:

    b = SQUARE(a);

    a++;

     

    建议:

    A.除非必要,应尽可能使用函数代替宏;

    B.常量建议使用const定义代替宏;

    C.宏定义中尽量不使用return、 goto、 continue、 break等改变程序流程的语句。


    6.注释

    原则:

    A.优秀的代码可以自我解释,不通过注释即可轻易读懂;

    B.注释的内容要清楚、明了,含义准确,防止注释二义性;

    C.在代码的功能、意图层次上进行注释,即注释解释代码难以直接表达的意图,而不是重复描述代码。


    规则:

    A.修改代码时,维护代码周边的所有注释,以保证注释与代码的一致性。不再有用的注释要删;

    B.文件头部应进行注释,注释必须列出:版权说明、版本号、生成日期、作者姓名、工号、内容、功能说明、与其它文件的关系、修改日志等,头文件的注释中还应有函数功能简要说明;

    C.函数声明处注释描述函数功能、性能及用法,包括输入和输出参数、函数返回值、可重入的要求等;定义处详细描述函数功能和实现要点,如实现的简要步骤、实现的理由、 设计约束等;

    D.全局变量要有较详细的注释,包括对其功能、取值范围以及存取时注意事项等的说明;

    E.注释应放在其代码上方相邻位置或右方,不可放在下面。 如放于上方则需与其上面的代码用空行隔开,且与下方代码缩进相同;

    F.避免在注释中使用缩写,除非是业界通用或子系统内标准化的缩写;

    G.同一产品或项目组统一注释风格。

     

    建议:

    A.避免在一行代码或表达式的中间插入注释;

    B.文件头、函数头、全局常量变量、类型定义的注释格式采用工具可识别的格式。

     

    7.排版与格式

    规则:

    A.程序块采用缩进风格编写, 每级缩进为4个空格;

    B.相对独立的程序块之间、变量说明之后必须加空行;

    C.一条语句不能过长,如不能拆分需要分行写。一行到底多少字符换行比较合适,产品可以自行确定;

    D.多个短语句(包括赋值语句)不允许写在同一行内,即一行只写一条语句;

    E.if、 for、 do、 while、 case、 switch、 default等语句独占一行;

    F.在两个以上的关键字、变量、常量进行对等操作时,它们之间的操作符之前、之后或者前后要加空格; 进行非对等操作时,如果是关系密切的立即操作符(如->),后不应加空格;

    G.注释符(包括/*‟„//‟„*/‟)与注释内容之间要用一个空格进行分隔。


    说明

    关于编程规范、原则等相关的文章在国外很多优秀的工程师都总结的有:

    http://www.artima.com/weblogs/viewpost.jsp?thread=331531

     

    良好的编程习惯是需要日积月累的,如果你处于学习阶段,请你时刻要注意这些细节问题。

    640?

    640?wx_fmt=jpeg

    1.大牛说他这样阅读STM32参考手册。。。

    2.新版IAR调试查看寄存器问题和STM8代码大小优化问题,本文来解决!

    3.适用于STM32的五大嵌入式操作系统,你选哪个?

    4.需求大还缺货,国产MCU为何仍受投资界“冷落”?

    5.华为22年,49岁,然而他一直在编码!

    6.开源的本质是什么,免费还是自由?640?wx_fmt=gif

    本文来自个人微信公众号「ID:strongerHuang」,经原作者授权发布。原文公众号由嵌入式工程师「strongerHuang」在精心整理并维护。专注分享的内容包含:Keil、IAR、STM8、STM32、μC/OS、FreeRTOS、CANOpen、ModBus...

    展开全文
  • 代码是写给人看的,不是写给机器看的,只是顺便计算机可以执行而已。...本文所写的是基于嵌入式软件开发之程序编程规范(四)的一些补充,针对于在编写代码时的容易忽略出错的写法、效率和可读性之间的均衡利弊。

    1、前言

    作为一个软件开发人员,应养成良好的编程习惯,随着编码越来越多,内容也会变得越来越多,规范化自己的编程有助于为了在程序代码量很大的时候,便于自己阅读,也便于别人阅读(团队合作),特别是作为一个合格的开发者,更需要规范自身写的程序代码,形成一种良好的习惯。

    记得之前看过一本书,其中我感触最深的一句话就是“代码是写给人看的,不是写给机器看的,只是顺便计算机可以执行而已”,好的习惯在编码时能事半功倍。

    在C语言中不遵守编译器的规定,编译器在编译时就会报错,这个规定叫作规则。但是有一种规定,它是一种人为的、约定成俗的,即使不按照那种规定也不会出错,这种规定就叫作规范。

    下篇:嵌入式软件开发之常用软件(六)


    1.1、目的

    本文所写的是基于嵌入式软件开发之程序编程规范(四)的一些补充,也融合了自己的一些看法:

    1、可读性和效率之间的取舍。

    2、避免粗心导致程序运行异常。

    1.2、参考文献

    • 《MISRA C编码规范标准》
    • 《华为C编程规范》
    • 《计算机程序的构造和解释》

    2、规范要求

    2.1、头文件

    对于C语言来说,头文件的设计体现了大部分的系统设计。 不合理的头文件布局是编译时间过长的根因,不合理的头文件实际上反映了不合理的设计。

    【规则 1】头文件中适合放置接口的声明,不适合放置实现

    1、内部使用的函数(相当于类的私有方法)声明不应放在头文件中

    2、内部使用的宏、枚举、结构定义不应放入头文件中

    3、变量定义不应放在头文件中,应放在.c文件中

    4、变量的声明尽量不要放在头文件中,亦即尽量不要使用全局变量作为接口。变量是模块或单元的内部实现细节,不应通过在头文件中声明的方式直接暴露给外部,应通过函数接口的方式进行对外暴露。 即使必须使用全局变量,也只应当在.c中定义全局变量,在.h中仅声明变量为全局的

    【规则 2】头文件应当职责单一,切忌依赖复杂

    头文件过于复杂,依赖过于复杂是导致编译时间过长的主要原因。很多现有代码中头文件过大,职责过多,再加上循环依赖的问题,可能导致为了在.c中使用一个宏,而包含十几个头文件,其根本原因是因为偷懒,想省事,所以往往会包含一大堆头文件,但是这种做法会导致编译时间拉长

    【规则 3】头文件应向稳定的方向包含

    头文件的包含关系是一种依赖,一般来说,应当让不稳定的模块依赖稳定的模块,从而当不稳定的模块发生变化时,不会影响(编译)稳定的模块,而且能及时中止编译,缩短因错误导致的编译时间。

    一般情况下为应用层头文件 > 模块层头文件 > 驱动层头文件 > 标准库头文件,根据代码后期可能修改的频率排序,如下代码,关于同一层的头文件排序方式,参考规则13

    include "app.h"      // 应用层头文件
    include "moudle.h"   // 模块层头文件
    include "device.h"   // 驱动层头文件
    include <string.h>   // 标准库头文件

    【规则 4】每一个 .c 文件应有一个同名 .h 文件,用于声明需要对外公开的接口

    如果一个.c文件不需要对外公布任何接口,则其就不应当存在,除非它是程序的入口,如main函数所在的文件。

    现有某些产品中,习惯一个 .c 文件对应两个头文件,一个用于存放对外公开的接口,一个用于存放内部需要用到的定义、声明等,以控制 .c 文件的代码行数,但是这种做法是不建议的。

    .h 文件可以不需要有对应的 .c 文件,如定义配置选项的一些头文件、或者定义了寄存器地址的宏等头文件可以不需要对应的 .c 文件。

    【规则 5】禁止头文件循环依赖

    原因:头文件循环依赖,如 a.h 包含 b.h,b.h 包含 c.h,c.h 包含 a.h 之类导致任何一个头文件修改,都导致所有包含了a.h/b.h/c.h的代码全部重新编译一遍

    做法:单向依赖,如 a.h 包含 b.h,b.h 包含 c.h,而 c.h 不包含任何头文件,则修改 a.h 不会导致包含了 b.h/c.h 的源代码重新编译

    【规则 6】.c/.h文件禁止包含用不到的头文件

    很多系统中头文件包含关系复杂,开发人员为了省事起见,可能不会去一一钻研,直接包含一切想到的头文件,甚至有些产品干脆发布了一个god.h,其中包含了所有头文件,然后发布给各个项目组使用,这种只图一时省事的做法,导致整个系统的编译时间进一步恶化,并对后来人的维护造成了巨大的麻烦

    【规则 7】头文件应当自包含

    自包含就是任意一个头文件均可独立编译。如果一个文件包含某个头文件,还要包含另外一个头文件才能工作的话,就会增加交流障碍,给这个头文件的用户增添不必要的负担

    【规则 8】总是编写内部 #include 保护符( #define  保护)

    在编写程序的头文件的时候,要注意每个头文件都应该用内部包含保护符来进行保护,以避免在多次包含时重新定义

    #ifndef FOO_H_INCLUDED_
    #define FOO_H_INCLUDED_
    
    //....文件内容.....
    
    #endif

    定义包含保护符时,应该遵守如下规则:

    • 保护符使用唯一名称;

    • 不要在受保护部分的前后放置代码或者注释(特殊情况:头文件的版权声明部分以及头文件的整体注释部分可以放在保护符(#ifndef XX_H)前面)

    【规则 9】禁止在头文件中定义变量

    原因:在头文件中定义变量,将会由于头文件被其他 .c 文件包含而导致变量重复定义编译报错

    只能在源文件中定义变量,在头文件中 extern 声明

    【规则 10】只能通过包含头文件的方式使用其他 .c 提供的接口,禁止在.c 中通过 extern 的方式使用外部函数接口、变量

    原因:

    1、若多处使用 extern 的方式声明使用,则改变变量类型或者函数的返回值等时需要改动的地方很多

    2、影响模块的稳定性,因为头文件声明的都是API接口,源文件(.c)中包含了私有函数和变量,有各自的执行条件,若通过 extern 的方式声明使用,则会降低模块的稳定性

    如:若 a.c 使用了 b.c 定义的foo()函数,则应当在b.h中声明extern int foo(int input);并在a.c中通过#include <b.h>来使用foo。禁止通过在a.c中直接写extern int foo(int input);来使用foo。

    【规则 11】禁止在 extern "C" 中包含头文件

    原因:在extern "C"中包含头文件,会导致extern "C"嵌套

    // 错误写法
    extern “C”
    {
    #include “xxx.h”
    ...
    }
    
    // 正确写法
    #include “xxx.h”
    extern “C”
    {
    ...
    } 

    【规则 12】一个模块通常包含多个 .c 文件,建议放在同一个目录下,目录名即为模块名。为方便外部使用者,建议每一个模块提供一个 .h ,文件名为目录名

    需要注意的是,这个.h并不是简单的包含所有内部的.h,它是为了模块使用者的方便,对外整体提供的模块接口。

    如:产品普遍使用的VOS,作为一个大模块,其内部有很多子模块,他们之间的关系相对比较松散,就不适合提供一个vos.h。而VOS的子模块,如Memory(仅作举例说明,与实际情况可能有所出入),其内部实现高度内聚,虽然其内部实现可能有多个.c和.h,但是对外只需要提供一个Memory.h声明接口

    【规则 13】同一产品统一包含头文件排列方式

    常见的包含头文件排列方式:功能块排序、文件名升序、稳定度排序。

    1、以功能块方式排列头文件可以快速了解涉及的相关功能模块

    2、以升序方式排列头文件可以避免头文件被重复包含

    3、以稳定度排序,如 product.h修改的较为频繁,如果有错误,不必编译platform.h就可以发现product.h的错误,可以部分减少编译时间


    2.2、函数

    函数设计的精髓:编写整洁函数,同时把代码有效组织起来。

    整洁函数要求:代码简单直接、不隐藏设计者的意图、用干净利落的抽象和直截了当的控制语句将函数有机组织起来。

    代码的有效组织包括:逻辑层组织和物理层组织两个方面。逻辑层,主要是把不同功能的函数通过某种联系组织起来,主要关注模块间的接口,也就是模块的架构。物理层,无论使用什么样的目录或者名字空间等,需要把函数用一种标准的方法组织起来。例如:设计良好的目录结构、函数名字、文件组织等,这样可以方便查找。

    【规则 1】一个函数仅完成一件功能

    一个函数实现多个功能给开发、使用、维护都带来很大的困难。

    将没有关联或者关联很弱的语句放到同一函数中,会导致函数职责不明确,难以理解,难以测试和改动。

    【规则 2】重复代码应该尽可能提炼成函数

    原因:重复代码提炼成函数可以带来维护成本的降低。

    1、当一段代码重复两次时,即应考虑消除重复,当代码重复超过三次时,应当立刻着手消除重复

    2、当一段代码逻辑相同,但是内部的部分变量和输出不同,可以进行提炼成函数,内部的不同变量作为入参等方式(有些逻辑相同的可以使用表驱动方式)

    【规则 3】避免函数过长,新增函数不超过 50 行 (非空非注释行) 

    原因:

    1、过长的函数往往意味着函数功能不单一,过于复杂

    2、延伸阅读材料: 业界普遍认为一个函数的代码行不要超过一个屏幕,避免来回翻页影响阅读(根据实际情况可以超过 50 行,自行把握)

    【规则 4】避免函数的代码块嵌套过深,新增函数的代码块嵌套不超过4层

    函数的代码块嵌套深度指的是函数中的代码控制块(例如:if、for、while、switch等)之间互相包含的深度

    原因:每级嵌套都会增加阅读代码时的脑力消耗,需要记住前一级的状态,不利于代码阅读

    做法:可以使用平级的代码控制块,如

    // 错误示例
    void serial(void)
    {
        if (...)
        {
            if (...)
            {
                if (...)
                {
                    ...;
                }
            }
        }
    }
    
    // 正确示例
    void serial(void)
    {
        if (!...)
        {
            return;
        }
    
        if (!...)
        {
            return;
        }
    
        ...;
    }

    【规则 5】对参数的合法性检查,如果公司有相关规定,则按照规定走,如果没有,则由接口函数负责。

    对于模块间接口函数的参数的合法性检查这一问题,往往有两个极端现象,即:要么是调用者和被调用者对参数均不作合法性检查,结果就遗漏了合法性检查这一必要的处理过程,造成问题隐患;要么就是调用者和被调用者均对参数进行合法性检查,这种情况虽不会造成问题,但产生了冗余代码,降低了效率。

    【规则 6】检查函数所有非参数输入的有效性,如数据文件、公共变量等

    函数的输入主要有两种:一种是参数输入;另一种是全局变量、数据文件的输入,即非参数输入。函数在使用输入参数之前,应进行有效性检查,防止调用者使用函数时传入不合理的入参,导致系统崩溃

    【规则 7】函数的参数个数不超过5个

    函数的参数过多,会使得该函数易于受外部(其他部分的代码)变化的影响,从而影响维护工作。函数的参数过多同时也会增大测试的工作量。

    函数的参数个数不要超过5个,如果超过了建议拆分为不同函数,或者使用结构体作为入参(结构体作为入参时,尽量使用使用指针传递,提高效率)

    【规则 8】函数中的不变参数或者函数入参在函数内不会改变使用 const 

    1、不变的值更易于理解/跟踪和分析,把 const 作为默认选项,在编译时会对其进行检查,使代码更牢固/更安全

    2、对应调用者而言,函数的入参如果是const, 则一眼就能明白哪些是入参

    void memcpy(void *pDst, const void *pSrc, int lenth)
    {
        ...
    }

    【规则 9】函数入参的定义顺序应是输出参数比输入参数先定义

    主要是统一规范,如函数 memcpy、sprintf、memset 等等,输出参数都是在函数的入参中先定义

    【规则 10】函数应避免使用全局变量、静态局部变量和 I/O 操作,不可避免的地方应集中使用

    实际开发过程中,难免会存在函数使用全局变量、静态局部变量和 I/O 操作,但是为了提高代码阅读性,建议集中使用

    【规则 11】在源文件范围内声明和定义的所有函数,除非外部可见,否则应该增加static关键字

    如果一个函数只是在同一文件中的其他地方调用,那么就用static声明。使用static确保只是在声明它的文件中是可见的,并且避免了和其他文件或库中的相同标识符发生混淆的可能性;且在阅读上能迅速了解哪些是非公开函数。


    2.3、变量

    【规则 1】一个变量只有一个功能,不能把一个变量用作多种用途

    一个变量只用来表示一个特定功能,不能把一个变量作多种用途,即同一变量取值不同时,其代表的意义也不同

    如,value在同一个函数中表示结果又表示次数,在阅读时增加了难度,所以这种做法是错的,正确的做法应该定义两个变量,分别表示不同含义

    【规则 2】结构功能单一,不要设计面面俱到的数据结构

    相关的一组信息才是构成一个结构体的基础,结构的定义应该可以明确的描述一个对象,而不是一组相关性不强的数据的集合。设计结构时应力争使结构代表一种现实事务的抽象,而不是同时代表多种。结构中的各元素应代表同一事务的不同侧面,而不应把描述没有关系或关系很弱的不同事务的元素放到同一结构中

    【规则 3】不用或者少用全局变量

    单个文件内部可以使用static的全局变量,可以将其理解为类的私有成员变量

    全局变量应该是模块的私有数据,不能作用对外的接口使用,使用static类型定义,可以有效防止外部文件的非正常访问

    若该模块内需要定义多个全局变量,可以统一整合成一个结构体句柄,在使用或者调试时会十分方便

    【规则 4】防止局部变量与全局变量同名

    虽然同名没有语法错误,但是函数会优先使用局部变量,同时增加阅读难度

    一般情况下,通过使用变量命名规范后,局部变量与全局变量同名基本不存在,最大前缀不同

    【规则 5】变量在定义时就需要初始化

    原因:若定义时没有初始化可能在一定条件下使用时出现错误,不利于后面排查问题

    【规则 6】严禁使用未经初始化的变量作为右值 

    在首次使用前初始化变量,初始化的地方离使用的地方越近越好。

    【规则 7】构造仅有一个模块或函数可以修改、创建,而其余有关模块或函数只访问的全局变量,防止多个不同模块或函数都可以修改、创建同一全局变量的现象

     降低全局变量耦合度

    【规则 8】使用面向接口编程思想,通过 API 访问数据:如果本模块的数据需要对外部模块开放 ,应提供接口函数来设置、获取,同时注意全局数据的访问互斥

    避免直接暴露内部数据给外部模型使用,是防止模块间耦合最简单有效的方法。定义的接口应该有比较明确的意义,比如一个风扇管理功能模块,有自动和手动工作模式,那么设置、查询工作模块就可以定义接口为SetFanWorkMode,GetFanWorkMode;查询转速就可以定义为GetFanSpeed;风扇支持节能功能开关,可以定义EnabletFanSavePower等。

    因为对外提供变量很难把控该变量被其他模块随意修改,影响系统的稳定性

    【规则 9】尽量减少没有必要的数据类型默认转换与强制转换

    当进行数据类型强制转换时,其数据的意义、转换后的取值等都有可能发生变化,而这些细节若考虑不周,就很有可能留下隐患

    错误示例:如下赋值,多数编译器不产生告警,但值的含义还是稍有变化。

    char ch;
    unsigned short int exam;
    ch = -1;
    exam = ch; // 编译器不产生告警,此时exam为0xFFFF。

     

    【规则 10】在定义变量时将其初始化

    定义的同时初始化效率更高,具体原因可自行百度;且也能防止野指针的出现,没有进行初始化程序运行时出错很难发现问题

    /* 先定义再赋值效率低 */
    int flag;
    
    flag = 1;
    
    /* 定义的同时赋值效率高 */
    int flag = 1;
    或
    int flag = GetFlag(); // 函数返回值赋值
    

    2.4、宏、常量

    【规则 1】用宏定义表达式时,要使用完备的括号

    因为宏只是简单的代码替换,不会像函数一样先将参数计算后,再传递。

    // 错误示例
    #define RECTANGLE_AREA(a, b) a * b     // RECTANGLE_AREA(1 + 2, 3 + 6) 替换时为 1 + 2 * 3 + 6, 因为符号优先级此时和想要的结果完全不同
    #define RECTANGLE_AREA(a, b) (a * b)
    #define RECTANGLE_AREA(a, b) (a) * (b) // 10 / RECTANGLE_AREA(1 + 2, 3 + 6) 替换时为 10 / (1 + 2) * (3 + 6), 结果不同
    
    // 正确示例
    #define RECTANGLE_AREA(a, b) ((a) * (b)) // RECTANGLE_AREA(1 + 2, 3 + 6) 替换时为 ((1 + 2) * (3 + 6)), 结果一致

    【规则 2】将宏所定义的多条表达式放在大括号中

    若宏定义函数表达式,则记得加换行符 \,建议使用 do{...}while(0) 的方式

    #define DOSOMETHING() \
    do \
    { \
    	fool1(); \
    	fool2(); \
    }while(0) \
    

    【规则 3】不允许直接使用魔鬼数字 

    使用魔鬼数字的弊端:代码难以理解;如果一个有含义的数字多处使用,一旦需要修改这个数值,代价惨重

    使用明确的物理状态或物理意义的名称能增加信息,并能提供单一的维护点。

    解决途径:对于局部使用的唯一含义的魔鬼数字,可以在代码周围增加说明注释,也可以定义局部const变量,变量命名自注释。对于广泛使用的数字,必须定义const全局变量/宏;同样变量/宏命名应是自注释的。0作为一个特殊的数字,作为一般默认值使用没有歧义时,不用特别定义

    【规则 3】除非必要,应尽可能使用函数代替宏

    宏对比函数,有一些明显的缺点:

    • 宏缺乏类型检查,不如函数调用检查严格;
    • 宏展开可能会产生意想不到的副作用,如#define SQUARE(a) (a) * (a)这样的定义,如果是SQUARE(i++),就会导致i被加两次;如果是函数调用double square(double a) {return a * a;}则不会有此副作用;
    • 以宏形式写的代码难以调试难以打断点,不利于定位问题;
    • 宏如果调用的很多,会造成代码空间的浪费,不如函数空间效率高。

    【规则 4】常量建议使用 const 定义代替宏

    当编译报错时,只会显示常量,不会显示宏定义的名字,查找时很费劲(因为宏是替换,在编译过程中称为“预处理”)

    一般情况下在意常量的类型,就使用const,如果是头文件对外提供的常量,使用宏定义

    【规则 5】宏定义中尽量不使用 return 、 goto 、 continue 、 break等改变程序流程的语句

    如果在宏定义中使用这些改变流程的语句,很容易引起资源泄漏问题,使用者很难自己察觉。

    错误示例:在某头文件中定义宏CHECK_AND_RETURN:


    2.5、表达式和基本语句

    【规则 1】赋值语句不要写在 if 等语句中,或者作为函数的参数使用

    因为 if 语句中,会根据条件依次判断,如果前一个条件已经可以判定整个条件,则后续条件语句不会再运行,所以可能导致期望的部分赋值没有得到运行

    如:if (test == 15 || HandleLogicFun()) {...},此时若 test = 15,则函数 HandleLogicFun 就不会执行

    【规则 2】用括号明确表达式的操作顺序,避免过分依赖默认优先级

    使用括号强调所使用的操作符,防止因默认的优先级与设计思想不符而导致程序出错;

    同时使得代码更为清晰可读,然而过多的括号会分散代码使其降低了可读性。

    一般代码行的运算符比较多就需要,如果很简单必要性不大,反而降低了美观性

    2.5.1、复合表达式

    【规则 1】不要编写太复杂的符合表达式

    太复杂的符合表达式不利于代码阅读

    如 i = a >= b && c < d && c + f <= g + h,过于复杂

    【规则 2】不要有多用途的符合表达式

    如 d = (a = b + c) + r 该表达式既求 a 值又求 d 值,应该拆分两个独立的语句:

    a = b + c;

    d = a + r;

    2.5.2、if 语句

    【规则 1】布尔变量与零值比较

    不可将布尔变量直接与 TRUE、FALSE 或者 1、0 进行比较,虽然基本不会有什么大问题,但是会影响阅读性

    根据布尔类型的语义,零值为“假” (记为 FALSE) ,任何非零值都是“真” (记为TRUE) 。TRUE 的值究竟是什么并没有统一的标准,例如 Visual C++  将 TRUE 定义为 1,而 Visual Basic 则将 TRUE 定义为-1;因此对于布尔变量,它与零值比较的标准 if 语句如下:

    if (flag)  // 表示 flag 为真
    {
    }
    
    if (!flag) // 表示 flag 为假
    {
    }

    【规则 2】整型变量与零值比较

    应当将整型变量用“==”或“!=”直接与 0比较。 

    对于整型变量,它与零值比较的标准 if 语句如下:

    if (flag == 0)
    {
    }
    
    if (flag != 0)
    {
    }

    【规则 3】浮点变量与零值比较

    不可将浮点变量用“==”或“!=”与任何数字比较。 
    千万要留意,无论是 float 还是 double 类型的变量,都有精度限制。所以一定要避免将浮点变量用“==”或“!=”与数字比较,应该设法转化成“>=”或“<=”形式。 
    假设浮点变量的名字为 x,应当将  if (x == 0.0)  // 隐含错误的比较转化为

    if ((x >= -EPSINON) && (x <= EPSINON))
    {
        ...
    }

    其中 EPSINON是允许的误差(即精度)

    【规则 4】指针变量与零值比较

    应当将指针变量用“==”或“!=”与 NULL比较,虽然和0比较基本不会有什么大问题,但是会影响阅读性,误以为该变量是其它类型
     指针变量的零值是“空” (记为 NULL) 。尽管 NULL 的值与 0 相同,但是两者意义不同。假设指针变量的名字为 p,它与零值比较的标准 if 语句如下:

    if (p == NULL) // p 与 NULL 显式比较,强调 p 是指针变量
    {
    }
    
    if (p != NULL) 
    {
    }

    【规则 5】若 if 有 else if 分支,则必须有 else 分支

    虽然没有else分支,但是在以后的代码维护中能清楚表明自己考虑了这种情况,但是目前不需要做任何处理

    if (...)
    {
        ...
    }
    else if (...)
    {
        ...
    }
    else
    {
        // TODO
    }

    其中表明注释 “TODO” 说明表明自己考虑了这种情况,但是目前不需要做任何处理

    【规则 6】对于 if ("变量" == "常量") 通常建议写成 if ("常量" == "变量")

    好处时能避免粗心大意写成 if ("变量" = "常量") ,而编译可能不会报错,最终代码运行时就会出现异常,而 if ("常量" == "变量") 这种写法若少了“=”,根据常量不能被赋值的规则,编译时就会报错。

    当然这种写法可能不美观,如果强迫症,那建议养成习惯后可以再恢复 if ("变量" = "常量") 这种写法,因为写该语句时都会下意识想到该规则,从而避免少写 = ,也能避免粗心引起的该问题。

    if (5 == test)
    {
    }
    
    if (NULL == pTest)
    {
    }

    2.5.3、for/while/do 循环语句

    循环语句有 for 语句,while 语句,do语句,其中 for 语句是使用频率最高的,以下规则1、2介绍如何提高 for 循环语句的效率,其根本是降低循环体的复杂性。

    【规则 1】在多重循环中,如果有可能,应当将最长的循环放在最内层,最短的循环放在最外层,以减少CPU跨切循环层的次数

    其中第二种就比第一种的运行效率要高,光从C代码角度看,区别不大,这个需要从汇编的角度看才能明显看出,具体可以自行尝试看执行时间(循环次数足够)看或者网上百度两种方式的对比,这里不再描述,网上比较详细;不过我建议是直接看两种编译后的汇编语句,这样感触最深。

    // 第一种
    for (i = 0; i < 100; i++)
    {
        for (j = 0; j < 10; j++)
        {
            ...
        }
    }
    
    // 第二种
    for (i = 0; i < 10; i++)
    {
        for (j = 0; j < 100; j++)
        {
            ...
        }
    }

    【规则 2】循环中存在判断语句等,根据实际情况选择

    如以下代码中判断表达式在循环体中,第二种就效率来说比第一种高,但是就代码简洁性来看,第一种更好,那么如何取舍呢?

    1、循环次数较少,可以采用第一种,原因是在循环次数较少的情况下,第二种的效率提高不明显

    2、底层驱动开发时,采用第一种往往会极大地影响效率,所以普遍采用第二种(之前开发LCD驱动时,画点时第二种比第一种在速度上明显提高)

    // 第一种
    for (i = 0; i < 10; i++)
    {
        if (...)
        {
            ...
        }
        else
        {
            ...
        }
    }
    
    // 第二种
    if (...)
    {
        for (i = 0; i < 10; i++)
        {
            ...
        }
    }
    else
    {
        for (i = 0; i < 10; i++)
        {
            ...
        }
    }

    【规则 3】不能再 for 循环体内修改循环变量,防止 for 循环失去控制

    下列代码容易失去控制

    for (i = 0; i < 10; i++)
    {
        if (...)
        {
            i += 2;
        }
        else
        {
            ...;
        }
    }

    【规则 4】建议 for 循环控制变量的取值采用“半开半闭区间”原则

    以下两种方式功能一样,但是第一种的写法更加直观

    // 第一种
    for (i = 0; i < N; i++)
    {
        ...
    }
    
    // 第二种
    for (i = 0; i <= N - 1; i++)
    {
        ...
    }
    

    【规则 5】空循环也应该使用{} 或者 continue,而不是一个简单的分号

    这样做的目的是直观地看出是一个空循环体

    for (i = 0; i < N; i++)
    {
    }
    
    while (flag)
    {
        condition;
    }
    

    2.5.4、switch 语句

    【规则 1】每一个switch语句最后都要写 default 分支,即使什么也不做

    这个和 else if 的 else 分支规则一样,目的是在以后的代码维护中能清楚表明自己考虑了这种情况,但是目前不需要做任何处理

    【规则 2】每个 case 语句的结尾别忘记加 break,否则导致多个分支重叠,除非是有意使多个分支重叠

    建议 case 和 break 成对编写,不要写了其他语句再写 break,防止遗忘,即使有意重叠,也应该这样做,写完后再删除 break

    2.5.5、goto语句

    【规则 1】尽量少用,但是我建议禁用更好,对于程序的阅读有很大的阻碍,如果必要可以采用 do{...}while(0) 的方式替代

    一般情况 goto 能解决退出函数时需要做的处理,如打开文件中间出现错误都需要关闭文件,不需要再退出的地方都写

    int ReadFileDate(char *pBuf, uint16_t lenth)
    {
        if (NULL == pBuf || 0 == lenth)
        {
            return;
        }
    
        if (open(file) == -1)
        {
            goto EOF;
        }
    
        if (read(file, pBuf, lenth) == -1)
        {
            goto EOF;
        }
    
        ...  // 其他处理,可能也存在错误需要退出处理(因为已经打开文件了)
    
    EOF:
        close(file);
    }
    

    这种方式如果禁用 goto,则基本每一个退出函数的地方都需要 close反而麻烦,此时可以通过do{...}while(0) 的方式替代

    int ReadFileDate(char *pBuf, uint16_t lenth)
    {
        if (NULL == pBuf || 0 == lenth)
        {
            return;
        }
    
        do
        {
            if (open(file) == -1)
            {
                break;
            }
    
            if (read(file, pBuf, lenth) == -1)
            {
                break;
            }
    
            ...  // 其他处理,可能也存在错误需要退出处理(因为已经打开文件了)
        } while (0);
    
        close(file);
    }

    2.6、其他建议

    【规则 1】变量的类型定义建议统一采用 uint8_t、uint16_t、int8_t 等定义

    根据8位、16位和32位等机器的不同,int 等类型所占的字节不一样,如果采用 int 等方式定义,那么在不同位机器移植代码时就会出现很多问题

    为了提高代码的移植性,一般采用 uint8_t、uint16_t、int8_t 等定义的方式,它是通过 typedef 定义的,而不是一种新的数据类型,typedef 定义的 uint8_t、uint16_t、int8_t 等可以更好的兼容各个平台,不用担心位不同机器造成的兼容性问题

    虽然也有用 u8、u16、u32 等其他typedef 定义方式,但是毕竟是少数,而uint8_t、uint16_t、int8_t 等定义的方式是业界通用的,具有更高的兼容性

    【规则 2】关于指针定义时的 * 的位置,建议是靠近变量或者函数

    如下列代码,靠近变量的*更能直观地看出该变量是指针

    uint8_t* src; // *靠近类型
    
    uint8_t *src; // *靠近变量
    
    uint8_t* GetInfo(void); // *靠近返回值类型
    
    uint8_t *GetInfo(void); // *靠近函数
    
    

    【规则 3】char 定义的字符串在申请内存或者定义大小时都需要留结尾标识'\0'空间

    strncpy 等安全函数在拷贝字符串到达指定长度时,不会再目标字符串结尾添加'\0',如果不手动添加'\0',则会出现意向不到的问题

    通常时在申请后立马清零或者定义时清零

    【规则 4】文件的编码格式尽量统一,如有中文,则统一为 utf8 的编码格式

    在单片机开发或者需要开发 LCD 驱动的情况,需要自己通过工具生成需要使用的中文字库(大多是 GB2312 格式),则需要留意该文件的编码格式,如果文件的编码格式是 utf8,则不能正常对应,如下是LCD 驱动的部分使用的字体库(一般为 GB2312 编码)

    /**
      * @brief      24 * 24 汉字字符集点阵索引
      * @note       对应点阵数据 LCD_FONT_24X24_DATA
      */
    const uint8_t LCD_FONT_24X24_IDX[] = {
        "参数"
    };
    
    /**
      * @brief      24 * 24 汉字字符集点阵数据
      */
    const uint8_t LCD_FONT_24X24_DATA[]= {
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x00,0x00,0x06,0x00,
        0x00,0x81,0x01,0xC0,0x00,0x06,0xE0,0xFF,0x0D,0x00,0x04,0x08,
        0x00,0x06,0x20,0xFC,0xFF,0x7F,0x00,0x41,0x00,0x80,0x91,0x00,
        0xC0,0x18,0x03,0x20,0x0C,0x0E,0x10,0xC3,0x78,0x8C,0x60,0x00,
        0x60,0x18,0x00,0x00,0x0C,0x06,0x00,0x83,0x03,0xE0,0xE0,0x00,
        0x00,0x38,0x00,0x00,0x0E,0x00,0xF8,0x01,0x00,0x00,0x00,0x00,/*"参",0*/
    
        0x00,0x00,0x00,0x00,0x80,0x00,0x80,0x81,0x01,0x88,0x98,0x00,
        0x90,0xCC,0x00,0xB0,0x44,0x00,0x90,0x4A,0x20,0xFC,0xDF,0x7F,
        0xC0,0x60,0x08,0xA0,0x67,0x08,0x90,0x5C,0x08,0x88,0x54,0x0C,
        0x84,0x48,0x0C,0xC0,0x80,0x04,0x40,0x8C,0x04,0xFC,0x8F,0x04,
        0x20,0x04,0x07,0x20,0x02,0x03,0xC0,0x03,0x03,0x80,0x8F,0x06,
        0x40,0x48,0x1C,0x30,0x30,0x78,0x0E,0x0C,0x10,0x00,0x00,0x00,/*"数",1*/
    }

    而在调用 LCD 的显示中文函数的文件为 utf8 编码格式,则程序运行时函数 LCD_ShowChinese 无法和字体库匹配(编码格式不一样)

    LCD_ShowChinese("参数");

    解决方式有两种:

    1、将调用 LCD 的显示中文函数的文件全部调整为 GB2312 编码格式,这样源码就存在 GB2312 和 utf8 的编码格式文件

    2、在函数 LCD_ShowChinese 增加 UTF8 转 GB2312 格式功能,这样就不需要将调用 LCD 的显示中文函数的文件转成 GB2312 编码格式了

     

     

     

     

     

     

     

     

     

    展开全文
  • 嵌入式软件设计规范

    2011-11-02 15:12:19
    一部很好的企业内部规范,适合C程序开发人员,爱好者
  • 嵌入式软件编程规范

    2015-12-31 11:36:00
    为了使变量能够更好被阅读代码的其他开发人员理解,需要使用前缀 •a(数组)、b(布尔值)、i(4字节整型)、u(无符号整型数)、p(指针)、s(字符串)、sz(以NULL结尾的字符串) --比如: bool bFlag; ...

     

    一、命名规范

    1、命名规范

    为了使变量能够更好被阅读代码的其他开发人员理解,需要使用前缀

    •a(数组)、b(布尔值)、i(4字节整型)、u(无符号整型数)、p(指针)、s(字符串)、sz(以NULL结尾的字符串)

      --比如:

      bool    bFlag;    

      int     iCount;     

      char    szName[NAME_LEN];

    •i,j,k,m,n,x,y,z 单字母变量可是使用在循环控制和索引处,不可滥用
    •局部静态变量在符合其他规则的基础上,必须加前缀s_,如s_bFlag。
    •全局变量在符合其他规则的基础上,必须加前缀g_,如:g_bFlag
    •如果一个变量既是全局变量又是静态变量,则使用g_即可,因为相对于静态类型,全局类型更需要突出
    •如果是一个结构体变量,可以使用stru_或者st_,视情况而定,不能使代码看起来太长,反而不容易阅读
     

    2、函数命名

    • 函数名由小写字母+下划线组成,在区别不同版本时可使用数字。
    • 多个单词使用下划线分割。
    • 函数名需加固定前缀,前缀形式:模块_,如:日志模块  log_write_alarm_entry()。
    • 函数名必须有明确意思,功能相反的函数使用反义词区别。

    --如:cfg_param_net_set();  cfg_param_net_get()。

        usr_account_add();    usr_account_del()。

    • 接口的多个版本命名可使用数字标识,以此区别不同版本,形式 _v1。

    --如:cfg_param_net_set() 旧;cfg_param_net_set_v1();  cfg_param_net_set_v2()

     

    3、结构体命名

    • 1. 结构体名由大写字母、数字和下划线组成,不允许使用小写字母。
    • 2.多个单词使用下划线分割。
    • 3. 结构体名必须加固定前缀:模块_,固定后缀: _T。
    •   [示例]:参数管理模块,pppoe参数     typedef struct {} CFG_PPPOE_PARAM_T, * PCFG_PPPOE_PARAM_T

     

    4、宏命名

    • 1.宏名由大写字母、数字和下划线组成,不允许使用小写字母。
    • 2.多个单词使用下划线分割。
    • 3.宏名必须加固定前缀,前缀形式:模块_。

    --[示例]:参数管理模块,用户名长度 #define  CFG_NAME_LEN  (32)

     

    二、宏的使用

    • 目前在代码中,宏主要有两种作用,首先是定义一个数值,另外就是条件宏,用来控制编译器进行有选择的代码编译
    • 数值宏在嵌套定义时,要加括号
      • #define SIZE (10*4)
      • #define NUM (1024/SIZE)

    上例中若SIZE 定义时不加括号,那么NUM 就替换成了1024/ 10*4,将导致NUM值出乎预料

    • 使用条件宏的过程中,若必须使用,则应避免过多的宏影响阅读

     

    三、注释风格

    1、错误修复和解决方法代码必须使用注释。

    修改代码时,总是使代码的注释保持最新, 为了防止问题反复出现,对错误修复和解决方法代码必须使用注释。

    2、在每个函数的开始,应该提供标准的注释。

            以指示例程的用途,注释样本应该是解释它为什么存在和可以做什么的简短介绍。

    3、在变量声明时,应在行尾添加注释;全局变量必须有注释。

    在这种情况下,将所有行尾注释应使用公共制表符(Tab)在一处对齐。

    4、对由循环和逻辑分支组成的代码使用注释。

    这些可以帮助源代码读者理解代码书写目的。

    5、为了使层次清晰,在闭合的右花括号后注释该闭合所对应的起点。

     

    转载于:https://www.cnblogs.com/shaosli/p/5091210.html

    展开全文
  • コーディング作法ガイドの読み方 組込みソフトウェア向けコーディング作法:作法表
  • 写在前面Ⅰ不知道大家有没有这样的感受:看到不规范(杂乱差)的代码,瞬间就没有看下去的欲望了。 相信大家看到标题都应该能明白编程的规范及原则对于每一个软件开发的工程师来说是...
  • 本文是作者本人在多年嵌入式软件开发中所总结出的一些经验,仅作读者参考。 一、排版格式 0.在同一个项目中的所有代码应保持一致的代码风格,引用第三方库文件源码的除外。 1.代码行首缩进使用TAB键,TAB宽度设置为...
  • 本标准是在理解标准C语言的基础上,结合嵌入式软件的开发实践以及嵌入式软件开发中常见的 不规范编码方式制定的,着重于软件的安全性、可读性,既可作为嵌入式软件开发中的编码要求,也可作 为软件交付时验收方的...
  • 代码是写给人看的,不是写给机器看的,只是顺便计算机可以执行而已
  • 嵌入式软件c编程规范

    2012-07-21 17:56:05
    本标准是在理解标准C语言的基础上,结合嵌入式软件的开发实践以及嵌入式软件开发中常见的危险编码方式制订的,着重于软件的安全性、可读性。
  • 这条规定乍一看有点奇怪,因为我们已经习惯了开发过程中使用tab键代替空格去分隔程序,为什么要求使用四个空格这种很傻很慢的操作?其实这里要求使用四个空格主要是因为在不同编辑器中对tab键的定义不同,如果混用...
  • c语言编程 :基础知识 库函数的熟悉和实现 开发规范 linux环境和程序设计:命令行 shell,unix高级编程 数据结构和算法:堆 栈 树 图,查找 排序的时间空间复杂度, 软件设计和实现技术: 编程思想 设计模式 重构...
  • 本文提出的软件开发方法基于Sireulink环境和OSEK OS规范。在Simulink环境下开发的算法可以结合OSEK RTOS(本文为修改过的μC/OS-II)直接应用到目标硬件上。该方法已通过实例进行了验证,与传统方法比较极大地缩短了...
  • 中科院苏州中科集成电路设计中心与上海科卓信息科技有限公司(科卓培训)联合举办的首个嵌入式软件开发免费讲座——《软件编程规范制定和执行》将于2011年10月21日在苏州举行,旨在与广大软件研发人员分享一下在软件...
  • 摘要 近年来,V型开发模式在汽车电子开发领域... 现在V型开发模式已成为使用最广的汽车软件开发流程标准。这一标准流程得到许多工具的支撑,有来自Mathworks的工具,如用于功能开发和仿真的Matlab/Simulink/Stateflo
  • 2.代码规范 3.确定最高效的开发工具 4.版本管理 5.问题定位 二.正文 1.流程管理  整个的流程可以分为几个小的部分:  1)开发需求确认流程  2)开发流程  3)测试版本发布提交流程    1)开发...
  • 规范化的设计让工程师工作更高效,这已经是不用争论的事实。现在在大型软件工程开发方面,这已经做得相当好。但在单片机和嵌入式系统的开发方面,规范化的工作却有待我们共同探讨。
  • 给大家推荐一篇模型设计的论文-基于Simulink和Stateflow建模的嵌入式软件开发平台研究.rar 给大家推荐一篇模型设计的论文, 2008年,电子科技大学,高权, 基于simulink和stateflow建模的嵌入式软件开发平台研究...
  •   源程序是指未经编译的,按照一定的程序设计语言规范书写的,人类可读的文本文件,源程序就是所写好的代码。   可执行程序,即常说的.exe程序,可以执行程序,完成计算机功能。在C语言中,.c文件就是所谓的...
  • 嵌入式C语言编程规范

    2016-06-16 10:13:26
    纵观历史的长河,软件是人类历史上复杂度最高的工业产品,没有之一! 优秀的代码是美丽的,... 本规范适用于公司内使用C语言编码的所有嵌入式软件。本规范自发布之日起生效,以后新编写的和修改的代码应遵守本规范
  • 嵌入式软件测试

    2015-03-30 12:22:32
    本书立足于工业实践, 旨在为有效控制复杂的嵌入式软件测试过程提供解决方案。书中全面讲述了嵌入式软件测试的一般过程,内容包括结构化测试和嵌入式系统的原理、测试生命周期、重要的应用技术、基础设施、测试组织...
  • 基于自动代码生成机制的嵌入式系统软件开发,李兰春,魏晋宏,随着自动代码生成技术的发展,基于技术文件规范的传统嵌入式软件开发模式逐渐被基于模型的设计方法所取代,后者实现了高效的代码
  • 今天痞子衡给大家讲的是飞思卡尔软件开发C语言编码规范。  2020鼠年春节是个漫长的假期,痞子衡在家百无聊赖,翻出了2016年10月1日(这个时间是痞子衡正式开始用markdown+github写技术文章并发表到博客园上的纪念日...
  • 研究从软件体系结构和应用开发过程两个角度对嵌入式应用开发作了改进和规范。在软件体系结构上采用了层模式和映像模式相结合的架构。在开发过程的规范和复用上采用了集成开发环境的思想。从改进后在实际应用开发中的...
  • 嵌入式软件解决方案

    2020-10-26 19:10:18
    建立嵌入式软件综和一体化设计/验证/开发/测试/确认/维护全寿命的系统平台,从而就需要构建一个即能满足嵌入式...使软件开发技术系统化、规范化、高效化,能稳步、可持续性发展,并保障软件的质量,提高软件的可靠性。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 439
精华内容 175
关键字:

嵌入式软件开发规范