MISRA C Rules

Overview

No

Item

Description

Sharer

1

MISRA C 2012 Rule 11.8

A cast shall not remove any const or volatile qualification from the type pointed to by a pointer

Zhu, Cuicui
2

MISRA C 2004 Rule 11.5

A cast shall not be performed that removes any const or volatile qualification from the type addressed by a pointer

Zhu, Cuicui

3

MISRA C Rule 9.3

In an enumerator list, the "=" construct shall not be used to explicitly initialize members other than the first, unless all items are explicitly initialized

Miao, Pu (uidk2146)

4

MISRA C 2012 Rule 15.6

The body of an iteration-statement or a selection-statement shall be a compound-statement

Duan, Yingying02
5

MISRA C 2004 Rule 14.9

An if (expression) construct shall be followed by a compound statement. The else keyword shall be followed by either a compound statement, or another if statement

Duan, Yingying02

6

MISRA C Rule 4.1

Only those escape sequences that are defined in the ISO C standard shall be used

Li, Xiang07
7

MISRA C 2012 Rule 6.1

Bit-fields shall only be declared with an appropriate type

Zhang, Yuzhu (uie78635)

8

MISRA C 2012 Rule 13.3

A full expression containing an increment (++) or decrement (--) operator should have no other potential side effects other than that caused by the increment or decrement operator

Zhang, Chao04

9

MISRA C 2012 Rule 16.1

All switch statements shall be well-formed

Nie, Xian (uie38246)

10

MISRA C Rule 8.3

For each function parameter the type given in the declaration and definition shall be identical, and the return types shall also be identical

Zou, Caixu (uif00680)

11

MISRA C Rule 6.1

The plain char type shall be used only for the storage and use of character values.

Xu, Songxue
12

MISRA C 2012 Rule 21.15

The pointer arguments to the Standard Library functions memcpy, memmove and memcmp shall be pointers to qualified or unqualified versions of compatible types

Xu, Junwen03 (uie96982)

13

MISRA C 2012 Rule 18.4

The +, -, += and -= operators should not be applied to an expression of pointer type

Wei, Xiya (uif00990)

14

MISRA C 2004 Rule 8.1

Functions shall have prototype declarations and the prototype shall be visible at both the function definition and call

Ding, Yue03 (uie64023)
15

MISRA C Rule 16.4

The identifiers used in the declaration and definition of a function shall be identical.

Duan, Yingying02

16

MISRA C 2012 Rule 8.4

A compatible declaration shall be visible when an object or function with external linkage is defined.

Zhu, Cuicui
17

MISRA C Rule 10.3

The value of a complex expression of integer type shall only be cast to a type of the same signedness that is no wider than the underlying type of the expression.

Zou, Caixu (uif00680)

18 MISRA C 2012 Rule 7.1 Octal constants shall not be used. Wei, Xiya (uif00990)
19 MISRA 2012 C Rule 3.2 Line-splicing shall not be used in // comments

Miao, Pu (uidk2146)

20
21

MISRA C 2012 Dir 4.6 
MISRA C 2004 Rule 6.3

typedefs that indicate size and signedness should be used in place of the basic numerical types

Zhang, Yuzhu (uie78635)

22 MISRA C 2004 Rule 8.1 Functions shall have prototype declarations and the prototype shall be visible at both the function definition and call. Xu, Songxue
23 MISRA C Rule 19.4 C macros shall only expand to a braced initialiser, a constant, a string literal, a parenthesised expression, a type qualifier, a storage class specifier, or a do-while-zero construct. Li, Xiang07
24 MISRA C 2012 Rule 11.4 A conversion should not be performed between a pointer to object and an integer type

Nie, Xian (uie38246)

25

MISRA C 2012 Rule 10.1

Operands shall not be of an inappropriate essential type

Xu, Junwen03 (uie96982)
26

MISRA C 2004 Rule 19.15

Precautions shall be taken in order to prevent the contents of a header file being included twice

Ding, Min
27

MISRA C Rule 5.5

No object or function identifier with static storage duration should be reused.

Dou, Zhixi (uidk3996)

28

MISRA C Rule 10.5

If the bitwise operators ~ and << are applied to an operand of underlying type ''unsigned char'' or ''unsigned short'', the result shall be immediately cast to the underlying type of the operand

Duan, Yingying02  

29

MISRA C 2012 Rule 20.10

The # and ## preprocessor operators should not be used

Zhang, Chao04

30

MISRA C 2012 Rule 8.11

When an array with external linkage is declared, its size should be explicitly specified

Zhu, Cuicui

31

MISRA C 2012 Rule 5.6
MISRA C 2004 Rule 5.3

A typedef name shall be a unique identifier

Zou, Caixu (uif00680)

32

MISRA C 2012 Rule 9.3

Arrays shall not be partially initialized

Miao, Pu (uidk2146)

33

MISRA C Rule 12.13

The increment (++) and decrement (--) operators should not be mixed with other operators in an expression.

Wei, Xiya (uif00990)

1 MISRA C 2012 Rule 11.8 & MISRA C 2004 Rule 11.5

1.1 Explanation

Rules 解读: 强制转换不应从指针指向的类型中删除任何const 或volatile 修饰符。
不遵循规则可能会出现以下问题:

  • 删除const修饰符,可能会绕过对象的只读状态,并导致对象被修改;
  • 删除const修饰符,可能会在访问对象时导致异常;
  • 删除volatile修饰符,可能会导致对对象访问被优化。

1.2 Example

uint16_t x;

uint16_t * const cpi = &x;         /* const pointer - 指针指向的内存地址是不可修改  */

uint16_t * const *pcpi;            /* pointer to const pointer - 指针指向的指针常量 */

uint16_t * *ppi;

const uint16_t *pci;               /* pointer to const - 指针指向的内存地址所对应的值是const,不可修改 */

volatile uint16_t *pvi;            /* pointer to volatile -  指针指向的内存地址所对应的值是volatile,不可优化 */

uint16_t *pi;                         

pi = cpi;                          /* Compliant - no conversion no cast required - 指针赋值常量指针无类型转换  */

pi  = (uint16_t *)pci;             /* Non-compliant  -  不合规,强制类型转换,删除const修饰符           */

pi  = (uint16_t *)pvi;             /* Non-compliant  -  不合规,强制类型转换,删除volatile修饰符      */

ppi = (uint16_t * *)pcpi;          /* Non-compliant  -  不合规,强制类型转换,删除const修饰符         */

2 MISRA C Rule 9.3

2.1 Explanation

Rules 解读: 在使用枚举变量时,如果没有使用“=”,默认第一个元素从0开始,后续元素依次加1。如果使用到“=”,请注意,要么只给首元素分配值,后续自动分配;要么给所有的元素都手动分配值。除此之外,如果枚举里面既有自动分配又有手动分配,是不被允许的。

2.2 Example

enum colour { red=3, blue, green, yellow=5 };  /* non compliant  不合理  */

  /* green和yellow都代表5,编译可以通过,但会有MISRA的warning */

enum colour { red=3, blue=4, green=5, yellow=5 };  /* compliant  合理    */

  /* green和yellow都代表5,编译可以通过,也不会报MISRA相关的warning */

3 MISRA C 2012 Rule 15.6 & MISRA C 2004 Rule 14.9

3.1 Explanation

Rules 解读:在使用while, do...while, for 循环或者if,else, switch 时,需要用复合语句。({.. }来定义复合语句)
不遵循规则可能会出现以下问题:

  • 开发人员可能误认为缩进对齐连续的代码都是其语句
  • 表达式后面意外包含分号, 导致空语句

3.2 Example

//误认为action_2() 属于第一层if(flag_1)

if ( flag_1 )

 if ( flag_2 ) /* Non-compliant */

 action_1 ( ); /* Non-compliant */

else

 action_2 ( ); /* Non-compliant */

//while 循环表达式后误跟分号导致空语句

while ( flag );  /* Non-compliant */

{

 flag = fn ( );

}

4 MISRA C Rule 4.1

4.1 Explanation

Rules 解读:在字符串中,只能使用ISO C标准中定义的转义序列/字符.
标准ISO/IEC 14882:2003[1]§2.13.2中定义的转义序列为:\n, \t, \v, \b, \r, \f, \a, \\, \?, \', \", \, \x

不遵循规则可能的结果:

  • 使用未定义的转义序列会导致未定义的行为

Tips:

  • 一个常见的错误 - 在字符串中,将“\\”写成“\”来表示字符“\”

4.2 Example

const char_t a[ 2 ] = "\k";    /* Non-compliant 不合理 */

const char_t b[ 2 ] = "\b";    /* Compliant 合理       */

#error "Please update TTALE__nu8ArrayBitsSize array size in pkg\ecusrv\hwttale\adapt\hwttale4ci.h!!!"

/* Non-compliant 不合理

 * In this string, compiler consider \e,\h,\a as undefined escape sequence(在上面这个字符串中,编译器会判定\e,\h,\a为未定义的转义字符)

 */

  

#error "Please update TTALE__nu8ArrayBitsSize array size in pkg\\ecusrv\\hwttale\\adapt\\hwttale4ci.h!!!"

/* Compliant 合理

 * here, \\ means '\'

 */

5 MISRA C 2012 Rule 6.1

5.1 Explanation

Rules解读:位域的使用对于定义类型有特殊要求。
在 C90 标准中 仅能使用在 由 unsigned int 和 signed int 定义的结构体成员或联合体成员
在 C99 标准中 新增了对 bool 类型支持
拓展应用在 由 typedef 的 unsigned int 和 signed int
例如 typedef unsigned int uint16; uint16 var : 1; 这样是可以的

不遵循规则可能会有以下问题:

  • 单纯使用 int 的话,无法表明是否有符号位,通常由compiler option 来确定
  • 如果是 enum, short, char 使用位域 在 C90 标准中是没有被定义的

5.2 Example

typedef unsigned int UINT_16;

struct s {

   unsigned int b1:2;    /* Compliant */

   int b2:2;             /* Non-compliant - plain int not permitted 没有表明 int 是否有符号*/

   UINT_16 b3:2;         /* Compliant - typedef designating unsigned int */

   signed long b4:2;     /* Non-compliant even if long and int are the same size 仅能使用上述所说的三种类型*/

};

6 MISRA C 2012 Rule 13.3

6.1 Explanation

Rules 解读: 不推荐将自加“++”或自减“--”运算符与其他的运算符在同一句代码中使用。

不遵循规则可能会出现以下问题:

  • 显著影响代码的易读性;
  • 由于序列点中对象被修改一次以上,操作结果是未定义的,故而可能会引入其他的未定义行为,见示case2.

6.2 Example

//case1

++u8b; u8a = u8b + u8c; u8c--;  //以上代码的易读性明显优于“u8a = ++u8b + u8c--;”

//case2

int x = 2;

int y = 5;

x = y * x++; //以上表达式中,在同一序列点中对x进行了两次赋值,最终算出的x值在不同的编译器中会有不同的结果,有些编译器会用10赋值,然后自增到11,有的编译器会先把x自增到3,然后再进行赋值运算,把x赋值为15.

7 MISRA C 2012 Rule 16.1

7.1 Explanation

Rules 解读: 要求所有switch语句都应格式正确。如果switch语句符合以下语法规则所指定的C switch语句子集,则应认为该语句格式良好。如果此处给出的语法规则与标准中定义的语法规则具有相同的名称,则它将替换switch语句范围的标准版本;否则,《标准》中给出的所有语法规则不变。

switch-statement:
switch ( switch-expression ) { case-label-clause-list final-default-clause-list }
switch ( switch-expression ) { initial-default-clause-list case-label-clause-list }

case-label-clause-list:
case-clause-list
case-label-clause-list case-clause-list

case-clause-list:
case-label switch-clause
case-label case-clause-list

case-label:
case constant-expression:

final-default-clause-list:
default: switch-clause
case-label final-default-clause-list

initial-default-clause-list:
default: switch-clause
default: case-clause-list

不遵循规则可能会出现以下问题: 
C语言中switch语句的语法不是特别严格,可以允许复杂的非结构化行为。此规则和其他规则在switch语句上施加了一个简单而一致的结构。不遵循上述规则,可能会导致出现MISAR Rule 16.2,Rule 16.3,Rule 16.4,Rule 16.5,Rule 16.6中描述的问题。

  • C语言允许在在switch语句主体中包含的任何语句之前放置switch标签(例如,大小写标签或默认标签),这可能导致非结构化代码。
  • 如果开发人员未能用break语句结束switch子句,则控制流“落入”下一个switch子句中,或者如果没有这样的子句,则从末尾进入switch语句后面的语句中。虽然有时会故意这样实现,但通常这是一个错误。
  • default 标签的要求是防御性编程。Default标签后面的任何语句都旨在采取适当的操作。如果没有任何处理,则可以使用注释来解释default中为什么没有采取具体行动。
  • 具有单一路径的switch语句,可能表示编程错误

7.2 Example

//case1

switch (x)

{

    case 1:        /*Compliant*/

        if (flag)

        {

    case 2:        /*Non-Compliant*/

        x = 1;

        }

        break;

    default:

        break;

}

//case2

switch (x)

{

    case 0:       

        break;     /*Compliant*/

    case 4:       

        a = b;     /*Non-Compliant - break omitted*/

    case 5:

        if (a == b)

        {  

            ++a;

            break/*Non-Compliant - conditional break*/

        }

    default:

        ;          /*Non-Compliant - default must also have a break*/

}

//case3

switch (x)

{

    case 0:

        ++x;   

        break;    

    case 4:       

        a = b;

        break;

    default:               /*Compliant- default label is present*/

        errorFlag = 1;     /*should be non-empty if possible    */

        break;       

}

//case4

switch (y)

{

    case 1:

    default:     /*Non-Compliant- switch is redundant*/

        y = 1;    

        break;

}

8 MISRA C Rule 8.3

8.1 Explanation

Rules 解读:函数的入参和返回值定义需与函数声明一致。
不遵循规则可能会出现以下问题:

  • 当出现兼容的数据类型时,会出现定义的参数不知道引用到哪个申明,强制类型转换会导致数据不匹配问题。

8.2 Example

typedef int32_t INT;

           INT i;

extern int32_t i;       // Non-compliant

        INT j;

extern  INT j;          // Compliant

extern void f (signed int);

       void f (int);                // Non-compliant

extern void g (const int);

       void g (int);                // Non-compliant

9 MISRA C Rule 6.1

9.1 Explanation

Rules解读:unsigned char 和 signed char可以用于数值计算,但是char的符号类型在C标准中是implementation defined,也就是没有明确定义,各个编译器的实现是不一样的,char型允许的操作符只有“=”“”“==”“”“!=”类型转换和三元运算符的第二第三操作数。
不遵循规则可能会有以下问题:

  • char型用作数字运算由于符号类型依赖于编译器实现,所以不同编译器执行结果可能不一样

9.2 Example

void GCMAN__vConvertStringtoInt(const char *pchInputAddr, void *pvDestAddr, uint32 u32Length)

{

   uint8 *pu8StorageAddr = NULL;

   char chTmpValue;

   pu8StorageAddr = pvDestAddr;

   do

   {

        chTmpValue = *pchInputAddr;

        chTmpValue -= 64; /*Non-compliant,the signedness of chTmpValue not sure, think about input char '0'*/

        *pu8StorageAddr = 64 + chTmpValue;

        pchInputAddr++;

        pu8StorageAddr++;

        u32Length--;

   }while (u32Length > 0);

}

10 MISRA C 2012 Rule 21.15

10.1 Explanation

Rules 解读: 使用memcpy, memmove and memcmp函数时,输入的的指针数据类型需要保持一致。
不遵循规则可能会出现以下问题:

  • 造成dest++ src++不匹配的问题;
  • 数组越界;

Tips:

  • 对于上述函数(memcpy, memmove and memcmp)的指针类型的入参,除了检查指向数据类型一致以外,需要确保入参的指针不是野指针或者空指针;

  • 出现内存重叠,内存重叠问题是指目的地址的内存空间的首地址,包含在源内存空间中,这两段内存空间有了交集,因而在使用memcpy进行内存复制操作时,这段重叠的内存空间会被破坏,这种情况在应用程序级代码中一般不会出现的,而在驱动或内核级代码中要十分小心,尽量使用memmove函数

  • 注意memmove这个函数名称中有"move"这个单词,而实际上src处的数据仍然还在,并没有真的被"移动"了!这个函数名称有它的历史原因,是因为有了memcpy函数后,发现这个函数有问题,又发明了另一个没有问题的memcpy函数,但为了保证兼容性依然保留了memcpy函数,而将新版本的memcpy函数改名为memmove函数

10.2 Example

void memcpy   void * restrict s1, const void * restrict s2, size_t n );

void memmove  void *s1, const void *s2, size_t n );

 int   memcmp   const void *s1, const void *s2, size_t n );

// Is it intentional to only copy part of 's2'

void f1 ( uint8_t s1[8], uint16_t s2[8] )

{

  void memcpy ( s1, s2, 8 );    /* Non-compliant */

}

// Is it intentional to only copy part of 's4'

void f2 ( uint8_t s3[8], uint8_t s4[8] )

{

  void memcpy ( s3, s4, 8 );    /* compliant */

}

/*

11 MISRA C 2012 Rule 18.4

11.1 Explanation

Rules 解读:指针不应使用 +, -, +=, -=运算符。使用数组下标 ptr[expr] 的数组索引是指针算法的首选形式。

不遵循规则可能会出现以下问题:

  • 任何显式计算的指针值都有可能访问意外或无效的内存地址。
  • 表达式 ptr+1 可能会被错误地解释为将 ptr 中保存的地址加 1。事实上,新的内存地址取决于指针目标的字节大小。如果 sizeof 应用不当,这种误解会导致意想不到的行为。

11.2 Example

void fn1 ( void )

{

  uint8_t a[10];

  uint8_t *ptr;

  ui nt8_t index = 0U;

  index = index + 1U;      /* Compliant - rule only applies to pointers */

  a[index] = 0U;           /* Compliant                                 */

  ptr = &a[5];             /* Compliant                                 */

  ptr = a;

  ptr++;                   /* Compliant - increment operator not +      */

  *(ptr + 5) = 0U;         /* Non-compliant                             */

  ptr[5] = 0U;             /* Compliant                                 */

}

12 MISRA C 2004 Rule 8.1

12.1 Explanation

Rules 解读:函数应具有原型声明,原型应在函数定义和调用时可见。

不遵循规则可能会出现以下问题:

  • 原型的使用使编译器能够检查函数定义和调用的完整性。如果没有原型,编译器就没有义务在函数调用中发现某些错误(例如,函数体的参数数量不同,调用和定义之间的参数类型不匹配)。功能接口已被证明是导致大量问题的原因,因此这一规则被认为非常重要。

Tips:

  • 为外部函数实现函数原型的推荐方法是在头文件中声明函数(即给出函数原型),然后将头文件包含在所有需要原型的代码文件中,为具有内部链接的函数提供原型是一种良好的编程习惯。

12.2 Example

c1.h

//function declaration

int add(int a, int b);

c1.c

#include "c1.h"

//function implementation

int add(int a, int b)

{

    return(a + b);

}

13 MISRA C Rule 16.4

13.1 Explanation

在函数定义和声明中用到的标识符应保持一致。

函数声明需要有返回类型,如果没有任何数据返回,可以用void. 类似的,如果函数没有传参,则传参要声明为void.
例如 void myfun(void);

不遵循规则可能会出现以下问题:
传参的命名有助于理解参数在函数中的用途。 如果函数传参正在在后续重新命名,则对同一对象使用不同名称,可能导致开发人员混淆。

13.2 Example

// File1

void CreateRectangle ( uint32_t Height, uint32_t Width );

  

// File2

// Non-compliant

void CreateRectangle ( uint32_t Width, uint32_t Height ); --> it will confuse the developer

void fn1 ( int32_t a );

void fn2 ( int32_t );

void fn1 ( int32_t b ) // Non-compliant --> rename the same object in definition.

{

}

void fn2 ( int32_t b ) // Compliant

{

}

16 MISRA C 2012 Rule 8.4(Required)

16.1 Explanation

当定义需要被外部引用的对象或者函数时,必须存在对应的声明。

当定义的对象或者函数,同时也存在对应的声明时候,编译器会检查定义和声明是否一致。

推荐做法:
对于需要被外部引用的对象或者函数,应将他们声明在一个头文件中,然后在被调用的文件及定义他们的文件中包含这个头文件。

16.2 Example

extern int16_t count;

       int16_t count = 0;                       /* Compliant */

extern uint16_t speed = 6000u;                  /* Non-compliant - no declaration prior to this definition      */

uint8_t pressure = 101u;                        /* Non-compliant - no declaration prior to this definition      */

extern void func1 ( void );

extern void func2 ( int16_t x, int16_t y );

extern void func3 ( int16_t x, int16_t y );

void func1 ( void )

{

  /* Compliant */

}

void func2 ( int16_t x, int16_t y )

{

  /* Compliant                                 */

}

void func3 ( int16_t x, uint16_t y )

{

  /* Non-compliant - parameter types different */

}

void func4 ( void )

{

  /* Non-compliant - no declaration of func4 before this definition      */

}

static void func5 ( void )

{

  /* Compliant - rule does not apply to objects/functions with internal linkage    */

}

17 MISRA C Rule 10.3 (required)

17.1 Explanation

复杂表达式类型转换,应转换为具有相同符号的类型,且不宽于表达式潜在类型。

17.2 Example

... (float32_t)(f64a + f64b)                   /* compliant     */

... (float64_t)(f32a + f32b)                   /* not compliant */

... (float64_t)f32a                            /* compliant     */

... (float64_t)(s32a / s32b)                   /* not compliant */

... (float64_t)(s32a > s32b)                   /* not compliant */

... (float64_t)s32a / (float32_t)s32b          /* compliant     */

... (uint32_t)(u16a + u16b)                    /* not compliant */

... (uint32_t)u16a + u16b                      /* compliant     */

... (uint32_t)u16a + (uint32_t)u16b            /* compliant     */

... (int16_t)(s32a - 12345)                    /* compliant     */

... (uint8_t)(u16a * u16b)                     /* compliant     */

... (uint16_t)(u8a * u8b)                      /* not compliant */

... (int16_t)(s32a * s32b)                     /* compliant     */

... (int32_t)(s16a * s16b)                     /* not compliant */

... (uint16_t)(f64a + f64b)                    /* not compliant */

... (float32_t)(u16a + u16b)                   /* not compliant */

... (float64_t)foo1(u16a + u16b)               /* compliant     */

... (int32_t)buf16a[u16a + u16b]               /* compliant     */

18 MISRA C 2012 Rule 7.1 (required)

18.1 Explanation

不应该使用八进制常数。

不遵循规则可能会出现以下问题:

开发人员可能误解为十进制常量。

注意:

此规则不适用于八进制转义序列,因为使用前导字符意味着混淆的范围较小。

写为单个数字的整数常量零严格来说是一个八进制常量,但这是此规则允许的例外。

18.2 Example

extern uint16_t code[ 10 ];

code[ 1 ] = 109; /* Compliant - decimal 109 */

code[ 2 ] = 100; /* Compliant - decimal 100 */

code[ 3 ] = 052; /* Non-Compliant - decimal 42 */

code[ 4 ] = 071; /* Non-Compliant - decimal 57 */

19 MISRA 2012 C Rule 3.2 (required)

19.1 Explanation

如果包含“//”的注释以“\”结尾,则下一行将成为注释的一部分,这可能会导致代码被意外删除。

19.2 Example

下面的示例是不合规的,if所在的行会被当成注释。

Example

extern bool_t b;

void f ( void )

{

    uint16_t x = 0; // comment \

    if ( b )

    {

        ++x; /* This is always executed */

    }

}

21 MISRA C 2012 Dir 4.6 & MISAR 2004 Rule 6.3

MISRA C 2012 Dir 4.6 typedefs that indicate size and signedness should be used in place of the basic numerical types
MISRA C 2004 Rule 6.3 (advisory): typedefs that indicate size and signedness should be used in place of the basic numerical types
Rules解读:
C关键字 char\short\int\long\float\double (signed or unsigned)这些C类型说明符在被使用是需要重新定义(typedef),不允许直接使用,原因有以下几点:
1、在嵌入式开发中对于存储空间的使用是非常重要的,通常开发人员往往需要确切的知道某个变量、常量、函数返回值等等具体需要占用多少存储空间,所以使用uint8_t比unsigned char更加直观的体现出大小是一个字节这个特点。
2、int这个关键字在C里面长度为2或4个字节,取决于MCU的位数,这就导致在不知道具体MCU的位数情况下没有办法单纯从代码中确切的知道某个被int定义的对象占用空间的大小。
基于以上原因对于执行C99标准的代码应当使用提供的类型,对于执行C90标准的代码应当定义和使用相同的类型,如下所示:

 展开源码


除了 int main (int argc, char* argv[]) 这种标准写法和位域的定义(参考上次分享位域使用)外,其余地方均不应该是直接使用int。
Example

 展开源码

22 MISRA C 2004 Rule 8.1

Functions shall have prototype declarations and the prototype shall be visible at both the function definition and call.
Rules解读:
函数原型可以帮助编译器完成许多的工作,同时,它也可以帮助程序极大的降低程序出错的几率。原型可以确保以下几点:
1,编译器正确处理函数返回值。
2,编译器检索使用的参数数目是否正确。
3,编译器检查使用的参数类型是否正确,如果不正确转换为正确的类型。
不遵循规则可能会出现以下问题:如果没有原型定义,编译器就没有义务在函数调用中发现某些错误(例如,函数体中的参数数量不同,调用和定义之间的参数类型不匹配
Example:

Example

double cube(double)

int main()

{

    int x = 5;

    double val = cube(x); //x will be conversion to double by compiler

}

double cube(double a)

{

    return x*x;

}

23 MISRA C Rule 19.4

MISRA C Rule 19.4 (required): C macros shall only expand to a braced initialiser, a constant, a string literal, a parenthesised expression, a type qualifier, a storage class specifier, or a do-while-zero construct.
Rules解读:
C宏只允许扩展为带括号的初始化式(braced initialiser)、常量(constant)、字符串(string literal)、带圆括号的表达式(parenthesised expression)、类型限定符(type qualifier)、存储类说明符(storage class specifier)或do{​}​while(0)构造。
1,类型限定符、存储类说明符包括关键字extern,static和const;
2,其它类型详见示例
 
不遵循规则可能会出现以下问题:
#define的任何其他用途都可能导致替换时出乎意料的行为,或者很难阅读的代码。
 
示例:

Example

/* The following are compliant */

#define PI 3.14159F                         /* Constant                      */

#define XSTAL 10000000                      /* Constant                      */

#define CLOCK (XSTAL/16)                  /* Constant expression           */

#define PLUS2(X) ((X) + 2)               /* Macro expanding to expression */

#define STOR extern                          /* storage class specifier       */

#define INIT(value){​ (value), 0, 0}​          /* braced initialiser            */

#define CAT (PI)                            /* parenthesised expression      */

#define FILE_A "filename.h"                /* string literal                */

#define READ_TIME_32() \

   do {​ \

      DISABLE_INTERRUPTS (); \

      time_now = (uint32_t)TIMER_HI << 16; \

      time_now = time_now | (uint32_t)TIMER_LO; \

      ENABLE_INTERRUPTS (); \

   }​ while (0) /* example of do-while-zero */

/* the following are NOT compliant */

#define int32_t long /* use typedef instead                     */

#define STARTIF if(  /* unbalanced () and language redefinition */

#define CAT PI       /* non-parenthesised expression            */

24 MISRA C 2012 Rule 11.4

A conversion should not be performed between a pointer to object and an integer type

Rules解读:
指针不应转为整数, 整数也不应转为指针

不遵循规则可能会出现以下问题:
1. 将一个整数转换为指向对象的指针,可能导致指针未正确对齐,从而引发未知的行为
2. 将指向对象的指针转换为整数, 可能会产生无法在所选整数类型中表示的值, 从而导致未知的行为

因此在可能的情况下,应避免在指针和整数类型之间进行强制转换。但是在寻址内存映射寄存器或者其他硬件特定功能时, 这种使用方式可能是必要的。 如必须使用整数和指针之前的强制转换,应确保生成的指针不会导致Rule11.3中讨论的未定义结果(MISRA C 2012 Rule 11.3: A cast shall not be performed between a pointer to object type and a pointer to a different object type)。

Example:

uint8_t *PORTA = ( uint8_t * ) 0x0002;    /* Non-compliant */

uint16_t *p;

int32_t  addr = ( int32_t ) &p;           /* Non-compliant */

uint8_t *q    = ( uint8_t * ) addr;       /* Non-compliant */

bool_t   b    = ( bool_t ) p;             /* Non-compliant */

enum etag { A, B } e = ( enum etag ) p;   /* Non-compliant */

25 MISRA C 2012 Rule 10.1

Operands shall not be of an inappropriate essential type

Rules解读:
操作数不应使用不恰当的基本类型

1.对浮点类型表达式(floating type)使用操作数是认为违反规则的。
2.对布尔类型(Boolean)表达式使用操作数,操作数应始终使用布尔值。
3.对被定义成数值作为操作数时,布尔类型(Boolean)操作数不应该使用。
4.对被定义成数值作为操作数时,字符类型(character)操作数不应该使用。
5.枚举类型的操作数不应用于算术运算,因为枚举对象本质上使用整数类型。所以涉及枚举对象的操作可能会产生具有意外类型的结果。(匿名枚举中的枚举常量本质上是有符号类型)。
6.移位和逐位操作应仅对无符号类型的操作数执行。
7.右移操作符应该针对无符号的类型操作数,以确保负移位不会导致未定义的行为。
8.一元减号运算符不应对无符号类型操作数进行操作。

Example:

enum enuma { a1, a2, a3 } ena, enb;  /* Essentially enum */

enum { K1 = 1, K2 = 2 };             /* Essentially signed      */

f32a & 2U           /* Non-Compliant - Rationale 1.constraint violation                   */

f32a << 2           /* Non-Compliant - Rationale 1.constraint violation                   */

cha && bla          /* Non-Compliant - Rationale 2.char type used as a Boolean value      */

ena ? a1 : a2       /*  Non-Compliant- Rationale 2.enum type used as a Boolean value      */

s8a && bla          /* Non-Compliant - Rationale 2.signed type used as a Boolean value    */

u8a ? a1 : a2       /* Non-Compliant - Rationale 2.unsigned type used as a Boolean value  */

f32a && bla         /* Non-Compliant - Rationale 2.floating type used as a Boolean value  */

bla * blb           /* Non-Compliant - Rationale 3.Boolean used as a numeric value        */

bla > blb           /* Non-Compliant - Rationale 3.Boolean used as a numeric value        */

cha & chb           /* Non-Compliant - Rationale 4.char type used as a numeric value      */

cha << 1            /* Non-Compliant - Rationale 4.char type used as a numeric value      */

ena--               /* Non-Compliant- Rationale 5.enum type used in arithmetic operation */

ena * a1            /* Non-Compliant - Rationale 5.enum type used in arithmetic operation */

s8a & 2             /* Non-Compliant - Rationale 6.bitwise operation on signed type       */

50 << 3U            /* Non-Compliant - Rationale 6.shift operation on signed type         */

u8a << s8a          /* Non-Compliant - Rationale 7.shift magnitude uses signed type       */

u8a << -1           /* Non-Compliant - Rationale 7.shift magnitude uses signed type       */

-u8a                /* Non-Compliant - Rationale 8.unary minus on unsigned type           */

bla && blb          /* Compliant  */

bla ? u8a : u8b     /* Compliant  */

cha - chb           /* Compliant  */

cha > chb           /* Compliant  */

ena > a1            /* Compliant  */

K1 * s8a            /* Compliant as K1 from anonymous enum */

s8a + s16b         /* Compliant  */

-( s8a ) * s8b     /* Compliant  */

s8a > 0            /* Compliant  */

--s16b             /* Compliant  */

u8a + u16b      /* Compliant  */

u8a & 2U        /* Compliant  */

u8a > 0U        /* Compliant  */

u8a << 2U       /* Compliant  */

u8a << 1        /* Compliant by exception              */

f32a + f32b    /* Compliant  */

f32a > 0.0     /* Compliant  */

26 MISRA C 2004 Rule 19.15

MISRA 2012 C Dir 4.10: Precautions shall be taken in order to prevent the contents of a header file being included more than once
MISRA C 2004 Rule 19.15 (required): Precautions shall be taken in order to prevent the contents of a header file being included twice.


Rules解读:
复杂嵌套关系下,有可能多次重复包含同一个头文件。如果这种多重包含重复的或者有冲突的定义,则会导致未定义的错误行为。一种常见的方法是为每个文件关联一个宏; 该宏在第一次包含文件时定义,随后在再次包含文件时使用以排除文件的内容。

"ahdr.h"可能有如下结构:

#ifndef AHDR_H

#define AHDR_H

/* The following lines will be excluded by the preprocessor if the file is included more than once */

文件内容...

#endif

或者

#ifdef AHDR_H

#error Header file is already included

#else

#define AHDR_H

/* The following lines will be excluded by the preprocessor if the file is included more than once */

...

#endif

Rule Link:

https://hi00126vmx.hi.cn.conti.de:8090/documentation/help/reference/misra.incguard.htm?checker.help=true

27 MISRA C Rule 5.5

MISRA C Rule 5.5 (advisory): No object or function identifier with static storage duration should be reused.
MISRA C++ Rule 2—10—5 (advisory): The identifier name of a non-member object or function with static storage duration should not be reused.

Rules 解读:不应重复使用具有static静态存储的变量或函数标识符。
不遵循规则可能会出现以下问题
开发人员可能会错误地将不相关的变量与相同的名称关联起来。

以下例子中,在同一个源文件的不同函数中使用了static静态变量相同标识符.

namespace NS1

{

    static int32_t global = 0;

}

namespace NS2

{

    void fn ( )

    {

        int32_t global; // Non-compliant

    }

}

28 MISRA C Rule 10.5

MISRA C Rule 10.5 (required): If the bitwise operators ~ and << are applied to an operand of underlying type ''unsigned char'' or ''unsigned short'', the result shall be immediately cast to the underlying type of the operand.
Rules 解读:
如果位操作 ~ 和<< 应用于基础类型 “unsigned char” 或者“unsigned short”, 结果应该立刻转换成操作数的基础类型。
不遵循规则可能会出现以下问题:因为当将这些运算符(~ 和 <<)应用于“unsigned char” 或者“unsigned short”,时,运算之前会进行整型提升,结果可能包含未预料到的高阶位。

uint8_t port = 0x5aU;

uint8_t result_8;

uint16_t result_16;

uint16_t mode;

result_8 = (~port) >> 4;             /* not compliant */

'~port' is 0xffa5 on a 16-bit machine but 0xffffffa5 on a 32-bit machine. In either case the value of 'result' is 0xfa, but 0x0a may have been expected. This danger is avoided by inclusion of the cast as shown below:

result_8 = ((uint8_t)(~port)) >> 4 ;               /* compliant */

result_16 = ((uint16_t)(~(uint16_t)port)) >> 4 ;   /* compliant */

A similar problem exists when the '<<' operator is used on small integer types and high order bits are retained. For example:

result_16 = ((port << 4) & mode) >> 6;             /* not compliant */

The value in 'result_16' will depend on the implemented size of an int. Addition of a cast avoids any ambiguity.

result_16 = ((uint16_t)((uint16_t)port << 4) & mode) >> 6;             /* not compliant */

No cast is required if the result of the bitwise operation is:

(a) immediately assigned to an object of the same underlying type as the operand;

(b) used as a function argument of the same underlying type as the operand;

(c) used as a return expression of a function whose return type is of the same underlying type as the operand.

29 MISRA C 2012 Rule 20.10

Rules 解读:
在进行宏定义的时候,与多个 #、多个 ## 或 # 和 ## 混合的预处理器运算符相关联的求值顺序是未指定的。因此,在某些情况下,无法预测宏展开的结果。同时,使用 ## 运算符可能导致代码不易理解。

举例:

#define A(Y) #Y        // 不合规则

#define A(X,Y) X##Y    // 不合规则

30 MISRA C 2012 Rule 8.11

Rules 解读:
声明带有外部链接的数组,应明确指定其大小。
--》此条规则只适用于非定义的声明。如果定义一个数组通过初始化隐式指定其大小是被允许的。

虽然可以声明一个不完整类型的数组并访问它的元素,但是当数组的大小被显示定义时,才更为安全。
为每个声明提供具体的数组大小,这样才可以检查它们的一致性,这样还可以允许静态检查器执行一些数组边界分析,而无需分析多个翻译单元。

举例:

extern int32_t array1[ 10 ]; /* Compliant */

extern int32_t array2[ ]; /* Non-compliant */


MISRA C 2004 Rule 8.12 (required): When an array is declared with external linkage, its size shall be stated explicitly or defined implicitly by initialisation.
Rules 解读:当用外部链接声明数组时,其大小应明确说明或通过初始化隐式定义。
举例:

int array1[ 10 ]; /* Compliant */

extern int array2[ ]; /* Not compliant */

int array2[ ] = { 0, 10, 15 }; /* Compliant */

31 MISRA C 2012 Rule 5.6 & MISRA C 2004 Rule 5.3
Rules 解读:tyoedef 名称应是唯一标识符
如果不唯一,会导致开发人员在开发过程中有困惑或者用错。
例外:如下例3,结构体、联合体和枚举类型的定义时的tag名可以与typedef名一样。
举例:

void func ( void )

{

  {

    typedef unsigned char u8_t;

  }

  {

    typedef unsigned char u8_t;     /* Non-compliant - reuse */

  }

}

typedef float mass;

void func1 ( void )

{

  float32_t mass = 0.0f;            /* Non-compliant - reuse */

}

typedef struct list

{

  struct list *next;

  uint16_t    element;

} list;                             /* Compliant - exception */

typedef struct

{

  struct chain

  {

    struct chain *list;

    uint16_t     element;

  } s1;

  uint16_t length;

} chain;                              /* Non-compliant - tag "chain" not associated with typedef */

32 MISRA C 2012 Rule 9.3

[MISRA C 2012 Rule 9.3 (required): Arrays shall not be partially initialized

Rules 解读:
为数组的每个元素提供显式初始化可以清楚的看到每个元素都被考到的了,所以当数组对象或者子对象的任何元素被显式初始化,则整个对象或子对象都应该被显式初始化。

大白话:
当数组被赋予初始化值,每个element都应该被赋予初始化值。

例外情况:
1.对于{0}格式的表示数组中所有对象都被赋值了
2.稀疏初始化可以只初始化指定的元素值
3.使用字符串初始化数组不需要对每个元素继续初始化

例子:

/* Compliant */

int32_t x[ 3 ] = { 0, 1, 2 };

/* Non-compliant - y[ 2 ] is implicitly initialized */

int32_t y[ 3 ] = { 0, 1 };

/* Non-compliant - t[ 0 ] and t[ 3 ] are implicitly initialized */

float32_t t[ 4 ] = { [ 1 ] = 1.0f, 2.0f };

/* Compliant - designated initializers for sparse matrix */

float32_t z[ 50 ] = { [ 1 ] =  1.0f, [ 25 ] = 2.0f };

In the following compliant example, each element of the array arr is initialized:

float32_t arr[ 3 ][ 2 ] =

{

  { 0.0f, 0.0f },

  { PI / 4.0f, -PI / 4.0f },

  { 0 } /* initializes all elements of array subobject arr[ 2 ] */

};

In the following example, array elements 6 to 9 are implicitly initialized to '\0':

char h[ 10 ] = "Hello"/* Compliant by Exception 3 */

33 MISRA C Rule 12.13

MISRA C Rule 12.13 (advisory): The increment (++) and decrement (--) operators should not be mixed with other operators in an expression.

Rules 解读:

++和--运算符不应与表达式中的其他运算符混合使用。

将++和--运算符与其他算术运算符结合使用,会显着影响代码的可读性,并可能导致未定义的行为。

例子:

u8a = ++u8b + u8c--;    /* Not compliant */

++u8b;    /* Compliant */

u8a = u8b + u8c;    /*  Compliant */

u8c--;    /* Compliant */


Rule Link:
https://hi00126vmx.hi.cn.conti.de:8090/documentation/help/reference/misra.decl.array_size.htm?checker.help=true

你可能感兴趣的:(c语言)