网站开发游戏程序开发宅男做网站

当前位置: 首页 > news >正文

网站开发游戏程序开发,宅男做网站,网站开发 方案,网站编排文章目录 说明Directives2 编译与构建Dir 2.1 3 需求可追溯性Dir 3.1 4 代码设计Dir 4.1Dir 4.2Dir 4.3Dir 4.4Dir 4.5Dir 4.6Dir 4.7Dir 4.8Dir 4.9Dir 4.10Dir 4.11Dir 4.12Dir 4.13 说明 以下等级一般分为三种#xff0c;建议#xff0c;必要#xff0c;强制 建议#… 文章目录 说明Directives2 编译与构建Dir 2.1 3 需求可追溯性Dir 3.1 4 代码设计Dir 4.1Dir 4.2Dir 4.3Dir 4.4Dir 4.5Dir 4.6Dir 4.7Dir 4.8Dir 4.9Dir 4.10Dir 4.11Dir 4.12Dir 4.13 说明 以下等级一般分为三种建议必要强制 建议建议准则应该在合理可行的范围内遵循这些条目。建议准则不需要正式偏差授权 必要声明符合本文件的 C 代码应符合所有必要准则如果有不符合项则应如第 5.4 节所述有正式的偏差声明。 强制声明符合本文档的C 代码应符合每项强制准则且不允许有偏离。 Directives 2 编译与构建 Dir 2.1 所有源文件都应通过编译且没有任何编译错误 等级该指令必要被执行 原理:有的编译器可能会尽管编译错误但仍会生成目标模块。但是执行生成的程序可能会产生意外的行为。 3 需求可追溯性 Dir 3.1 所有代码应可追溯到书面要求 等级该指令必要被执行 原理:所有的程序代码都应该是项目功能需要的例如开发员人debug时的代码应该在量产时被删除否则可能导致输出异常影响其他控制器。 追溯代码到文件化要求的方法应由项目决定。 一种实现可追溯性的方法是对照相应的已针对需求进行审核过的设计文档来审核代码。 4 代码设计 Dir 4.1 运行时的故障应尽量减少 等级该指令必要被执行 原理:C 语言设计提供非常有限的内置的运行时检查。虽然这种方法可以生成紧凑而快速的可执行代码但是它将运行时检查的负担放在了程序员身上。因此为了达到预期的健壮性水平程序员必须仔细考虑在可能发生运行时错误的地方添加动态检查。 运行时故障一般包括以下可能 ◆ 算术错误这包括在表达式求值中出现的错误例如上溢下溢被零除或因移位而丢失有效位。 在考虑整数溢出时请注意无符号整数计算不会严格溢出而是会产生确定的值但可能是意料之外的值。 应仔细考虑算术表达式中的值范围和运算顺序。该项在编写程序时时常需要注意 ◆ 指针算术确保在动态计算地址时计算出的地址是合理的并且指向有意义的地方。特别需要确保的是如果一个指针指向数组中的某个点那么当指针被增加或以其他方式改变时它仍然指向同一个数组中的某个点。参见指针算法的限制—Rule 18.1、Rule 18.2 和 Rule 18.3。 ◆ 数组超限错误在使用数组索引对数组进行索引之前请确保数组索引在数组大小的范围内—Rule 18.1。该项在编写程序时时常需要注意 ◆ 函数参数在将参数传递给库函数(Dir 4.11)之前应检查其有效性 ◆ 指针引用除非指针已知为非 NULL否则在引用指针之前应进行运行时检查。一旦进行了检查在单个函数中推断指针是否已经更改以及是否需要另一个检查就相对简单了。跨函数边界进行推理要困难得多特别是在调用其他源文件或库中定义的函数时。 ◆ dynamic memory 动态存储如果正在执行动态内存分配则必须检查每个分配是否成功并且设计并测试了适当的降级或恢复策略 Dir 4.2 汇编语言的所有运用都应记录在案 等级该指令建议被执行 原理:应该记录使用汇编语言的基本原理以及 C 和汇编语言之间的接口连接机制。 Dir 4.3 汇编语言应被封装和隔离 等级该指令必要被执行 原理使用汇编语言说明的地方应将它们封装和隔离在下述结构中 ◆ 汇编语言函数 ◆ C 语言函数(C99 首选内联函数) ◆ C 语言宏。 出于执行效率的考虑有时必须嵌入简单的汇编指令例如启用/禁用中断。若有必要(嵌入汇编指令) 则建议使用宏或内联函数(C99)来实现。 封装汇编语言的益处 ◆ 提高可读性 ◆ 封装宏或函数的名称和文档清楚地说明了汇编指令的意图 ◆ 所有执行相同指定功能的汇编语言代码可以共享相同的封装从而提高可维护性 ◆ 当实现方案或静态分析变动时封装后的汇编语言可以轻松的被替换。 注意内联汇编语言的使用是对标准C 的扩展因此它违反了 Rule 1.2。 Dir 4.4 代码段不应被“注释掉” 等级该指令建议被执行 原理代码中的未参与编译的部分应该使用条件编译实现例如 #if 0 … #endifDir 4.5 具有相同可见性的相同名称空间中的标识符在印刷/屏幕显示上应明确 等级该指令建议被执行 原理:同一段代码中的相同名称空间下列字符不能同时存在于两个变量中 大写与小写如id2_abc与id2_ABC不要同时存在 带下划线与不带下划线如 id1_a_b_c与id1_abc 字母“ O”和数字“ 0”,如id6_O和id6_0 字母“ I”和数字“ 1”,如id4_I和 id4_1 字母“ I”和字母“ l”,如id4_I和id4_l 字母“ l”和数字“ 1”,如id4_l和 id4_1 字母“ S”和数字“ 5”,如id4_S和 id4_5 字母“ Z”和数字“ 2”,如id5_Z和 id5_2 字母“ n”和字母“ h”,如id5_n和 id5_h 字母“ B”和数字“ 8”,如id7_B和 id7_8 字母序列“ rn”(“ r”后跟“ n”)和字母“ m”,如id8_rn和 id8_m int32_t id9_rn; struct {int32_t id9_m; /* Compliant(这里合规是因为它和上面的 id9_rn 不是同一命名空间) / };Dir 4.6 应使用指示大小和符号的 typedef 类型代替基本数字类型 等级该指令建议被执行 基本数字类型(charshortintlonglong long(C99)floatdouble 和long double)不应被使 用而应使用由 typedef 定义的特定长度的数字类型。 原理这个实际代码中使用的很多autosar标准数据type中也有定义如unsigned char被typedef为uint8 Dir 4.7 如果函数返回错误信息则应测试该错误信息 等级该指令必要被执行 使用一个函数(无论它是标准库的一部分第三方库还是用户定义的功能)都可以视为提供了一些指示错误发生的方法。 这可以通过错误标志某些特殊的返回值或其他方式进行。 每当函数提供这种机制时调用程序应在函数返回后立即检查错误指示。 但是请注意检查函数的输入值被认为是比在函数完成后尝试检测错误更可靠的错误预防方法(请参见Dir 4.11)。 Dir 4.8 如果指向结构体或联合的指针在转换单元中从未解引用则应该隐藏该对象的实现 等级该指令建议被执行 原理在使用结构体或联合体时如果没有进行解引用即访问内部的数据定义则应该通过指针操作. 示例 / Opaque.h */ #ifndef OPAQUE_H #define OPAQUE_H typedef struct OpaqueType pOpaqueType; #endif / Opaque.c / #include Opaque.h struct OpaqueType {/ Object implementation / }; / UseOpaque.c / #include Opaque.h void f ( void ) {pOpaqueType pObject;pObject GetObject ( ); / Get a handle to an OpaqueType object /UseObject ( pObject ); / Use it… / }在C文件中进行具体的结构体/联合体的定义在头文件通过指针定义该数据类型。实际访问时不会访问具体的内部数据保证内部数据不会被意外修改。 Dir 4.9 应该优先使用函数而不是类函数的宏因为它们是可互换的 等级该指令建议被执行 原理在大多数情况下应该使用函数而不是宏。函数执行参数类型检查并对其参数求值一次从而避免了潜在的多重副作用问题。在许多调试系统中步进执行函数比步进执行宏更容易。 尽管如此宏在某些情况下可能是有用的。 在决定使用函数还是宏时应考虑下述因素 •函数参数和结果类型检查的好处; •C99中内联函数的可用性尽管注意内联函数的作用程度是由实现定义的; •代码大小和执行速度之间的权衡 •编译时求值的可能性是否重要:带有常量参数的宏更有可能在编译时求值而不是相应的函数调用; •参数是否对函数有效:宏参数是文本的而函数参数是表达式; •易于理解和可维护性 示例 以下示例符合标准。 这些类似函数的宏不能用函数替换因为它具有 C 操作符作为参数 #define EVAL_BINOP( OP, L, R ) ( ( L ) OP ( R ) ) uint32_t x EVAL_BINOP ( , 1, 2 );在下面的示例中使用宏初始化具有静态存储持续时间的对象是合规的因为此处不允许进行函数调用。 #define DIV2(X) ( ( X ) / 2 ) void f ( void ) {static uint16_t x DIV2 ( 10 ); / 合规 - 此处不允许函数调用 /uint16_t y DIV2 ( 10 ); / 违规 - 此处允许函数调用 / }Dir 4.10 应采取预防措施以防止头文件的内容被包含多次 等级该指令必要被执行 原理这个也很常见在头文件中需要“头文件卫士” 示例 / file.h / #ifndef FILE_H / 违规 - 缺少 #define FILE_H / #endif为了便于检查应使用下列两种形式之一对头文件的内容进行保护避免多次包含。 start-of-file #if !defined ( identifier ) #define identifier/ Contents of file / #endif end-of-file start-of-file #ifndef identifier #define identifier/ Contents of file */ #endif end-of-fileDir 4.11 应该检查传递给库函数的值的有效性 等级该指令必要被执行 原理标准库中的许多函数都不检查传递给它们的参数的有效性。而且即使标准中要求进行检查或编译器作者声称检查参数的情况下也不能保证进行充分的检查。 类似地其他库中的函数的接口描述可能不会指定这些函数执行的检查。还有一个风险是指定的检查不一定充分执行。 编程人员应为所有具有限制输入域的库函数(标准库、第三方库和内部库)提供适当的输入值检查。 标准库中具有受限域并需要检查的函数示例如下: •math.h中的许多数学函数例如: 负数不能传递给sqrt或log函数;fmod的第二个参数不能为零 •当函数 toupper 传递一个非小写字母的参数(tolower 也有一样的问题)时某些实现可能会产生意外结果; •如果传递无效值ctype.h中的字符测试函数会显示未定义的行为; •应用于最负整数的abs函数给出了未定义的行为 尽管math.h中的大多数数学库函数定义了允许的输入域但是当发生域错误时它们返回的值可能因编译器而异。因此预先检查输入值的有效性对这些函数尤为重要 编程人员应该识别任何领域约束这些约束应该合理地应用于正在使用的函数(可能在接口描述中记录也可能没有记录)并提供适当的检查以确保输入值位于该域中。当然如果需要可以通过了解参数表示的内容以及参数值的合理范围来进一步限制该值 我们可以通过多种方式来满足本准则的要求包括 •在调用函数之前检查值; •检查调用的库函数中的值——这尤其适用于内部设计的库但如果供应商能够证明他们已经内置了检查则可以适用于购买的库; •生成执行检查的函数的“包装”版本然后调用原始函数; •静态地演示输入参数永远不能取无效值 Dir 4.12 不应使用动态内存分配 等级该指令必要被执行 此规则适用于所有的动态内存分配的封装包括 ◆ 标准库提供的内容 ◆ 第三方软件包。 原理标准库的动态内存分配和释放例程可能导致规则21.3中描述的未定义行为。任何其他动态内存分配系统都可能表现出与标准库类似的未定义行为。 应检查第三方例程的规范以确保动态内存分配没有被无意中使用 如果决定使用动态内存应注意确保软件以可预测的方式运行。例如存在以下风险: •可用内存可能不足以满足请求-必须注意确保对分配失败有一个安全和适当的响应 •根据使用模式和产生的碎片程度执行分配或重新分配所需的执行时间差异很大 示例 为了方便起见这些示例都是基于使用标准库的动态内存函数因为它们的接口是众所周知的 在本例中在第一次调用free之后由于指针p的值变得不确定因此该行为是未定义的。尽管在调用free之后存储在指针中的值保持不变但在某些目标上它所指向的内存可能不再存在并且复制该指针的行为可能导致内存异常 #include stdlib.h void f ( void ) {char *p ( char * ) malloc ( 10 );char q;free ( p );q p; / Undefined behaviour - value of p is indeterminate */p ( char * ) malloc ( 20 );free ( p );p NULL; /* Assigning NULL to freed pointer makes it determinate / }如果要使用malloc必须要保证释放后的指针为NULL Dir 4.13 为对资源提供操作而设计的函数应该按适当的顺序调用 等级该指令建议被执行 在资源上提供操作的一组函数通常有三种操作: 分配资源例如打开文件;资源的释放例如关闭文件;其他操作例如从文件中读取。 对于每一组这样的函数对其操作的所有使用都应按适当的顺序进行。 原理静态分析器工具能够提供路径分析检查可以通过程序识别导致未调用序列的释放函数的路径。为了使这种自动检查的好处最大化因此鼓励开发人员通过设计和声明静态分析器的平衡函数集来启用这些检查。 示例 / These functions are intended to be paired / extern mutex_t mutex_lock ( void ); extern void mutex_unlock ( mutex_t m ); extern int16_t x; void f ( void ) {mutex_t m mutex_lock ( );if ( x 0 ){mutex_unlock ( m );}else{/ Mutex not unlocked on this path */} }加锁和解锁需要按顺序调用