C语言编程规范_第1页
C语言编程规范_第2页
C语言编程规范_第3页
C语言编程规范_第4页
C语言编程规范_第5页
已阅读5页,还剩35页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

C语言编程规范,背景 意义 1,注释 2,标示符 3,类型 4,常量, 5,声明和定义 6,初始化 7,算术类型转换 8,指针类型转换 9,表达式,10,控制表达式 11,控制流 12,Switch语句 13,函数 14,指针和数组 15,结构体和联合体 16,预处理指令 17,标准库,背景 C语言是开发嵌入式应用的主要工具,然而C语言并非是专门为嵌入式系统设计,相当多的嵌入式系统较一般计算机系统而言对软件安全性(可靠性)有更苛刻的要求,所以因此会带来更多的安全隐患。,阿丽亚娜5型火箭爆炸瞬间,1996年6月4日,阿丽亚娜5型运载火箭的首航,原计划将运送4颗太阳风观察卫星到预定轨道,但因软件引发的问题导致火箭在发射39秒后偏轨,从而激活了火箭的自我摧毁装置。阿丽亚娜5型火箭和其他卫星在瞬间灰飞烟灭。(见图3) 后来查明的事故原因是:代码重用。阿5型的发射系统代码直接重用了阿4型的相应代码,而阿4型的飞行条件和阿5型的飞行条件截然不同。此次事故损失3.7亿美元 软件缺陷的代价极其昂贵。2002年,美国国家标准与技术研究所的一项研究表明,软件缺陷给美国每年造成的损失高达595亿美元。想想全球这个数额会是多大。,编码规范的意义: C语言在铁路行业的应用,安全可靠性非常重要,所以遵守一定的编程规范的显得尤为重要,公司的C语言编码规范(安全系统)是基于2004年的Guidelines For The Use Of The C Language in Critical Systems而编写。 1、养成良好的编码习惯,摒弃那些可能存在风险的编程行为。编写出安全健壮的代码,进而保证我们产品的可靠性、稳定性、安全性; 2、增加软件的可读性,便于日后维护; 3、遵循良好的共通的编码规范,也是项目开发中相互协作开发的技术基础。,规则2.2 (强制)源代码只能采用/*/风格的注释。(MISRA C:2004-Rule 2.2) 规则2.3 (强制)字符序列/*不能在注释中使用。(MISRA C:2004-Rule 2.3) 任何在注释中出现的“/*“字符序列都是违背本规则的。 #include “c_standards.h“ * *禁止使用嵌套的注释。 */ void static_function(void) * *这样的字符序列不符合规则 * ,规则5.1 (强制)内部或外部的标识符的识别都不能依赖于 31 个字符之后的差异。(MISRA C:2004-Rule 5.1) 便于编译器识别,代码清晰易读,并保证可移植性。 规则5.2 (强制)内部标识符不能使用和外部标识符相同的名字,导致在内部范围内隐藏外部标识符。(MISRA C:2004-Rule 5.2) 示例: int16_t i ; void f(void) int16_t i; /*这是一个不同的内部变量*/ i=3; /*代码不易理解,不知道这个 i 指那个变量*/ 国军标与本规则对应的准则:过程名禁止被重用;禁止参数与全局变量同名。如 下例:,# include “c_standards.h” void foo (uint32_t P_1) uint32_t x = P_l; void static_function (void) uint32_t foo = 1u; /*过程名静止被重用。*/ #include “c_standardsh“ /*- -Global Declarations* uint32_t dwTmp = 0; void static p(uint32_t dwTmp) /*禁止参数与全局变量同名。 */ */ ,规则6.1 (强制) 普通 char 类型只能用来存储字符值。(MISRA C:2004-Rule 6.1) 规则6.2 (强制)signed 和 unsigned char 只能作为数据值存储和使用。(MISRA C:2004-Rule 6.2) 有三种方式声明 char 类型:signed char; unsigned char 和 char 类型。前两种只能用于数值型数据,后一种用于字符数据。char 类型是否具有符号特性与具体的编译器有关。 对于声明为 char 类型的变量,只有三种操作符可以使用,即:=, =, !=。 规则6.3 (强制) 位域只能被定义为 unsigned int 或者 signed int 类型。(MISRA C:2004-Rule 6.4) 本规则与编译器的以下不确定行为有关: 未定义的行为:位域中的元素使用 signed int/unsigned int 以外的类型定义。 用 int 定义位域中的元素时,可能被处理为 signed int 或者 unsigned int,取决于具体的编译器。,规则6.4 (强制) signed int 类型的位域元素的长度至少为 2 bit。(MISRA C:2004-Rule 6.5) 1 bit 的 signed int 类型是没有意义的。 struct bs signed int a:1; /*只有一位没有意义,没有符号位*/ signed int b:2; /*符合规则*/ signed int c:3; /*符合规则*/ bit,*pbit; 规则7.1 (强制) 禁止使用八进制数及八进制转义序列。(MISRA C:2004-Rule 7.1),规则8.1 (强制) 函数都应该有原型声明,且对函数定义和调用可见。(MISRA C:2004-Rule 8.1) 要求程序使用原型声明,是利用编译器检查函数调用时数据类型的一致性。如果调用函数时,没有进行原型声明,则编译器不会检查出函数形参与实参的个数、类型等的不一致。函数接口问题已经被证明是一些重大软件问题的原因,因此本条规则尤为重要。 对外部函数来说,我们建议采用如下方法,在头文件中声明函数(亦即给出其原型) ,并在所有需要该函数原型的代码文件中包含这个头文件(见规则 8.8) 。 为具有内部链接的函数给出其原型也是良好的编程实践。,规则8.2 (强制) 无论对一个对象和函数声明或定义时,它的类型都应该显式声明。(MISRA C:2004-Rule 8.2) 示例: extern x; /*错误,没有类型说明*/ extern int16_t x; /*正确*/ const y; /*错误,没有类型说明*/ const in16_t y; /*正确*/ static foo(void); /*错误,没有类型说明*/ static int16_t foo(void); /*正确*/,规则8.3 (强制) 每个函数声明中的参数类型及返回值应与函数定义一致。(MISRA C:2004-Rule 8.3) 函数声明中的参数类型及返回值应与函数定义中的一致,包括 typedef 名称、限定词都需一致,而不仅仅是基本类型一致。 #include “c_standards.h“ FLOAT_32 static_function(UINT_32,UINT_16); SlNT_32 static_function(UINT_32 p_l,UINT_16 p_2) /* 定义的函数返回值与声明中不一致 */ SINT_32 result = 0; /* * return result: ,规则8.5 (强制) 头文件中不要定义对象或者函数。(MISRA C:2004-Rule 8.5) 如果该头文件被多个文件包含,会产生重复定义错误。当源文件包含某一头文件时,预处理器会将头文件的内容在包含指令处展开。显然,在头文件中函数的定义会在其他源文件中一模一样的出现,导致函数被重复定义。解决这一问题的关键是明确一个概念:所有可执行的代码或者对象和函数的定义都应在.C 的源文件中,头文件中只能存在其声明。具体的做法是:为全局变量的声明增加 extern 修饰符,并在相应的. C 源文件中定义对象或函数。 /* 在 Globle. h 中 */ extern uint32_t GCounter ; /* 在 GlobleVariables. C 中*/ uint32_t GCounter ;,规则8.7 (强制) 对象如果只被单个函数访问,应定义在块作用域。(MISRA C:2004-Rule 8.7) 对象的作用域应尽可能限制在单个函数内, 只有在对象需要内部或外部链接属性时才可在文件域声明,此时应遵守规则 8.10 的约束,即在文件域声明的对象应尽可能具有内部链接属性。如非必要,好的做法是尽量避免全局变量。 选择是在最外一层的块域还是在最内一层的块域声明对象, 很大程度上是编码风格的问题。 规则8.8 (强制) 一个外部变量或者函数只能在文件中被声明一次。(MISRA C:2004-Rule 8.8) 一般来讲,对于外部变量和函数的声明都放在一个头文件中,任何定义或引用这些外部对象的源文件需包含这个头文件。 示例: /* 在 FeatureX.h 中 */ extern int16_t a; /* 在 FeatureX.c 中*/ int16_t a = 0 ;,规则8.10 (强制) 所有在文件域中声明的对象或函数应具有内部链接属性(除非必须在别的文件中使用这个对象或函数)。(MISRA C:2004-Rule 8.10) 如果变量仅在本文件的函数中使用,则应使其具有内部链接属性,即对变量的声明使用 static 关键字。同理,如果一个函数仅在本文件的其它函数中调用,也使用static 关键字。使用 static 声明是为了确保该标识符仅对本文件可见,因而避免相同的标识符在其它文件或库文件中出现而引起的混淆。 规则8.12 (强制) 如果一个数组具有外部链接属性,那么它的大小需显式说明,或者通过初始化隐式定义。(MISRA C:2004-Rule 8.12) 示例: extern int array2 /*可以通过编译,但不满足本规则*/ extern int array310 /* 满足规则 */ int array110; /*满足规则*/ int array2=1,2,3; /*满足规则*/,规则9.1 (强制) 所有自动对象变量在使用之前都应该赋值。(MISRA C:2004-Rule 9.1) 本规则与编译器的以下不确定行为有关: 未定义的行为:一个存储属性为 auto 的对象在初始化之前的值。 本条款的目的是确保所有的变量在引用之前已经被写入了确定的值。 但本规则不要求必须在定义的时候初始化。 根据 ISO 标准,如果没有显式的初始化,具有静态存储属性的变量默认会自动初始化为 0。但实际上许多嵌入式编译环境并没有执行这个操作。 静态存储指一种存储属性,使用 static 关键字声明、或具有外部链接属性的变量具有静态存储属性。具有 auto 存储属性的变量通常不会自动初始化。 void static_function(void) int t,k; t=k+1; /* k 在定义前被使用 */ ,规则9.3 (强制) 枚举列表中,“=“只能用于第一个成员初始化(除非所有的成员都已初始化)。(MISRA C:2004-Rule 9.3) 如果一个枚举列表没有显式的初始化,C 语言会从 0 开始递增为每个元素自动赋值。 如果只为第一个元素显式的赋值,则后续元素从第一个元素的值开始,自动依次递增。使用这种方法初始化枚举列表是本规则允许的,但需要确认后续的值不会超过 int 表示的范围。 对所有元素显式的初始化也是本规则允许的,但不允许自动赋值和人工赋值混和。同时,程序员应确认所有的值都在规定范围内。 示例: enum color red=3, blue, green, yellow=5 ; /* 不符合本规则 */ enum color red=3, blue=4, green=5, yellow=5 ; /* 符合本规则 */,规则10.1 (强制) 以下情况下,整型表达式的值不允许隐式转换为其它不同的底层类型: 1. 整型操作数不是被扩充为更多位数的相同符号特性的整数;或 2. 表达式是复杂表达式;或 3. 表达式不是常数表达式,且是函数的参数;或 4. 表达式不是常数表达式,且是函数的返回表达式。 (MISRA C:2004-Rule 10.1) 规则10.2 (强制) 以下情况下,浮点数表达式的值不允许隐式转换为其它不同类型: 1. 浮点型操作数不是被扩充为更多位数的同符号浮点数; 2. 表达式是复杂表达式; 3. 表达式是函数的参数; 4. 表达式是函数的返回表达式。 (MISRA C:2004-Rule 10.2),规则10.3 (强制) 整数类型的复杂表达式的结果只允许转换为(与表达式底层类型相比)更窄的同符号特性的数据类型。(MISRA C:2004-Rule 10.3) 规则10.4 (强制) 浮点类型的复杂表达式的结果只允许转换为更窄的浮点类型。(MISRA C:2004-Rule 10.4) 规则10.5 (强制) 如果位操作符或移位操作符)作用于底层类型为unsigned char 或者 unsigned short 类型的操作数时,中间运算步骤的结果必须立刻显式转换为预期的底层类型。(MISRA C:2004-Rule 10.5) /*执行以下程序,result_8 的值? */ uint8_t port = 0x5aU ; uint8_t result_8 ; result_8 = (port) 4 ; result_8 = (uint8_t)(port) 4; result_16 = (uint16_t)(uint16_t)port) 4;,规则10.6 (强制) 所有无符号型的常量后必须加“U“。(MISRA C:2004-Rule 10.6) 规则11.1 (强制) 禁止函数指针和除整型外的任何数据类型相互转换。(MISRA C:2004-Rule 11.1) 规则11.2 (强制)指向某一类型对象的指针,除整型、其它对象指针以及 void 指针外,禁止与其余类型相互转换。(MISRA C:2004-Rule 11.2) 规则11.3 (强制) 指针转换过程中不允许丢失指针的 const,volatile 属性。(MISRA C:2004-Rule 11.5) 规则12.1 (强制)表达式的值必须在任何求值顺序下保持一致。(MISRA C:2004-Rule 12.2),规则12.2 (强制)不允许将 sizeof 运算符作用于有 side-effect 的表达式上。(MISRA C:2004-Rule 12.3) int32_t i = 0 ; int16_t j = 0; j = sizeof (i = 1234); 规则12.3 (强制) 逻辑运算( ,规则12.4 (强制)逻辑运算符(“&”或“|”)的操作数必须是一个基本表达式。(MISRA C:2004-Rule 12.5) 这里基本表达式包括标识符、常量和括号括起来的表达式。 规则12.5 (强制) 不允许对底层类型为有符号的类型进行位操作。(MISRA C:2004-Rule 12.7) 规则12.6 (强制) 移位操作的右操作数只能在 0 和操作数的位数减 1 之间。(MISRA C:2004-Rule 12.8) 规则12.7 (强制) 不允许对底层类型为无符号的表达式进行一元负(“-”)运算符。(MISRA C:2004-Rule 12.9) 规则12.8 (强制) 不允许使用逗号表达式。(MISRA C:2004-Rule 12.10),规则12.9 (强制) 不得以位的形式操作或表示浮点型数值。(MISRA C:2004-Rule 12.12) 规则13.1 (强制) 赋值表达式不能用在需要布尔值的地方。(MISRA C:2004-Rule 13.1) uint8_t x ,y ; if (x = y) foo( ); 规则13.2 (强制) 不允许对浮点数进行相等或者不相等的比较。(MISRA C:2004-Rule 13.3),规则13.3 (强制) for 循环的控制表达式不应包含浮点数类型。(MISRA C:2004-Rule 13.4) 规则13.4 (强制) for 语句中的 3 个表达式只能和循环控制相关。(MISRA C:2004-Rule 13.5) 规则13.5 (强制) for 循环中,循环计数变量不允许在循环体中修改。(MISRA C:2004-Rule 13.6) flag = 1; for (i=0; (i5) /* 不符合规则 */ ,规则13.6 (强制) 禁止使用结果为常量的布尔表达式。(MISRA C:2004-Rule 13.7) 如果使用一个布尔表达式, 但这个表达式的结果可以证明总为 “真” 或总为 “假” ,这种情况很大可能是代码错误。 if (u16a 20) /* 不符合规则:恒为 FALSE */ if (s8a 10) if (s8a 5) /* 不符合规则:恒为 TRUE */ ,规则14.1 (强制) 不得遗留“不可到达”的代码。(MISRA C:2004-Rule 14.1) switch (event) case e_wakeup: do_something(); break; /* 绝对跳转 */ do_more(); /* 不符合规则:不能到达的代码 */ default: /* */ break; 如果一个函数没有在任何地方被调用,则整个函数都是“不可到达”的。,规则14.2 (强制)所有非空语句必须满足如下任意一条: a) 产生至少一个 side-effect (side-effect 指表达式执行后对程序运行环境造成的影响。赋值语句、自增操作等都是典型的具有side-effect 的操作) ; 改变程序控制流。(MISRA C:2004-Rule 14.2) x = 3; /* 不符合规则:x 与 3 比较,然后结果被丢弃了 */ 规则14.3 (强制) 一行中如果有空语句,那么该行只能有这条空语句,除注释外不能有别的语句,并且在这条空语句前不能有注释,注释必须在其后,用空白字符隔开。(MISRA C:2004-Rule 14.3) ; /*符合规则*/ /*不符合规则:注释放在空语句之前*/ ; ;/* 不符合规则:注释与空语句之间没有空白字符 */ 规则14.4 (强制) 不得使用 goto 语句。(MISRA C:2004-Rule 14.4),规则14.5 (强制) 不得使用 continue 语句。(MISRA C:2004-Rule 14.5) 规则14.6 (强制) 一重循环中最多只能出现一个 break 语句用于结束循环。(MISRA C:2004-Rule 14.6) 规则14.7 (强制) 函数只能有一个出口,这个出口必须在函数末尾。(MISRA C:2004-Rule 14.7) 规则14.8 (强制)switch、while、do. . . while 和 for 语句的主体必须是复合语句(即用大括号包含) ,即使该主体只包含一条语句。(MISRA C:2004-Rule 14.8) 规则14.9 (强制) if 结构后面必须是一个复合语句(即用大括号包含) ,else 后面必须是一个复合语句(即用大括号包含) 或者另一个 if 语句。(MISRA C:2004-Rule 14.9),规则14.10 (强制) if . . . else if 结构必须由一个 else 子句结束。(MISRA C:2004-Rule 14.10) 这个原则与规则 15.3中,switch 语句必须有 default 分支的原则是一致的。 规则15.2 (强制)所有非空的 switch 子句都应该用 break 语句结束。(MISRA C:2004-Rule 15.2) 规则15.3 (强制)switch 的最后一个分支必须是 default 分支。(MISRA C:2004-Rule 15.3) 规则15.4 (强制) switch 表达式的值不能是布尔值。(MISRA C:2004-Rule 15.4) 例如,以下例子是不符合本规则的: switch (x=0) /* 不符合规则:x=0 是布尔值表达式 */,规则15.5 (强制) 每条 switch 语句必须包含至少一个 case 分支。(MISRA C:2004-Rule 15.5) switch (x) uint8_t var; /* 不符合规则: 在第一个 case 语句之前定义*/ case 0: a = b; break; /* 这里的 break 是必须的 */ case 1: /* 空的分支中可以不用 break */ case 2: a = c; if (a = b) case 3: /* 不符合规则:case 3 最内的上层复合语句是 if 的主体 */ case 4: a = c; /* 不符合规则:不为空的分支必须以 break 结束 */ default: /* 必须有 default 语句 */ errorflag =1; /* default 分支尽量不为空 */ break; ,规则16.1 (强制) 不允许定义参数数量不确定的函数。(MISRA C:2004-Rule 16.1) 规则16.1 (强制) 不允许定义参数数量不确定的函数。(MISRA C:2004-Rule 16.1) 规则16.3 (强制) 在函数的原型声明中应给出所有形参的标识符。(MISRA C:2004-Rule 16.3) 规则16.4 (强制) 在函数声明和定义中使用的标识符应当一致。(MISRA C:2004-Rule 16.4) 规则16.5 (强制) 无形参的函数应将形参类型声明为 void 类型。(MISRA C:2004-Rule 16.5),规则16.7 (强制) 非空返回值的函数的所有退出路径必须有一显式的带表达式的return 语句。(MISRA C:2004-Rule 16.8) 规则16.8 (强制) 函数标识符只允许以下两种用法:使用一个&前缀+函数标识符,或者函数标识符+(参数列表)。参数列表可以为空。(MISRA C:2004-Rule 16.9) if( fun ) /* 不符合规则*/ /*.*/ ,规则17.1 (强制) 只有指向数组的指针才允许进行指针算术运算。(MISRA C:2004-Rule 17.1) 此处的指针算术运算只仅仅限定于指针加减某个整数,比如 ppoint = ppoint - 5, ppoint+等。对于不是指向类似 array 对象的元素的指针,执行加或减的操作是没有定义的。 即使是指向 array 对象元素的指针, 由于不能保证运算后得到的是有效的地址 (比如超过数组长度),所以对指针进行代数运算是不安全的,应谨慎对指针进行代数运算。 规则17.2 (强制) 只有指向同一个数组的两个指针才允许相减。(MISRA C:2004-Rule 17.2) 指针的相减操作只有在它们指向同一个 array 对象时,结果才是充分定义的,例如,UINT_16 *q = p + i, 那么可以通过 q-p 得到 i

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论