上周为公司研发人员出了一份MISRA-C的试卷,作为前段时间关于MISRA-C培训的一个总结和摸底。等试题出完,批阅试卷的时候,发现少许问题,果然自己出题时还是有考虑不周的情况。以下是相关题目和解析,抛砖引玉与大家分享,忘网友不吝赐教。由于word格式的问题,可能有些地方不是很详细,忘见谅。
1. 下列关于MISRA-C的描述正确的是 C
A MISRA-C是一款C语言开发工具,它保证了关键系统中使用编程语言的安全性;
B MISRA-C是C语言衍生出的另外一种语言,类似于C++,它保证了关键系统中使用编程语言的安全性;
C MISRA-C是C语言的一个子集,它保证了关键系统中使用编程语言的安全性;
D MISRA-C是对C语言的一个扩展,它保证了关键系统中使用编程语言的安全性
2. 请判断下列哪个行为的结果不需要存在文档化说明 D
A 位域存储 B sizeof C 浮点数 D typedef
解析:规则3.5:位域存储需要文档化;Sizeof是实现定义的行为,需要文档化;
规则1.5:浮点应用应该适应于已定义的浮点标准,则应该存在文档;
3. 假如可以重用某些标识符,以下哪些行为的标识符名称可以考虑重用C
A typedef的名称 B tag的名称 C 不同结构体中成员名称 D 函数标识符名称
解析:
规则5.3:typedef 的名字应当是唯一的标识符;
规则5.4:标签(tag )名称必须是唯一的标识符
规则5.6:一个命名空间中不应存在与另外一个命名空间中的标识符拼写相同的标识符,除了结构和联合的成员名字。
4. 对于int8_t octal_const的使用,判断下列哪项是错误的 B
A octal_const = 0; B octal_const = 00; C octal_escape = '\0'; D octal_const = 0x17;
解析:
规则7.1:不应使用八进制常量(零除外)和八进制序列;
5. 判断如下声明或定义中,不正确的一项 A
A static mc2_1b ( void ); B int16_t explicit_int = 0;
C static voidmc2_1a ( void ); D const int_16 implicit_int = 0;
解析:A选项没有声明函数的返回值;
规则8.2:无论何时声明和定义一个对象和函数,它的类型都应该是显式声明;
6. 以下外部连接标识符的声明,错误的选项是 C
A extern int32_tex_array1 [ 5 ];
B extern int32_tex_array2 [ 3 ];
C extern int32_tn_ex_array [ ];
D extern void mc2_fun( void );
解析:C选项数组大小没有声明;
规则8.12:当一个数组声明为具有外部链接,它的大小应该显式声明或者通过初始化进行隐式定义
7. 当#define ARRAY_SIZE 5U时,下列对数组的定义,请判断错误的选项为 C
A static int32_t mc2_array_1 [ ARRAY_SIZE ] = {0 };
B static int32_t mc2_array_2 [ ARRAY_SIZE ] = {0 , 1, 2, 3, 4 };
C static int32_t mc2_array_3 [ ARRAY_SIZE ] = {1 };
D static int32_t mc2_array_3 [ ARRAY_SIZE-2 ][ARRAY_SIZE-3] = { { 1, 2 }, { 3, 4 }, { 5, 6 } } ;
解析:C选项初始化与数组大小不匹配;数组或结构的元素可以通过只初始化其首元素的方式初始化(为0或NULL )。
规则9.2:应该使用大括号以指示和匹配数组和结构的非零初始化构造。
8. 关于位运算,其中u8r、u8a为8位无符号整型,s8r、s8a为8位有符号整型,以下正确的语句是 C
A u8r = ( uint8_t) ~u8a; B s8r = ( sint8_t ) ~s8a
C u8r = ( uint8_t) (~u8a) >>4; D u8r = ( uint8_t ) ~(u8a>> 4);
解析:D明显违反了10.5,(u8a >> 4)没有转换就进行位非~操作。
规则10.5:如果位运算符 ~和 << 应用在基本类型为unsignedchar 或unsigned short 的操作数,结果应该立即强制转换为操作数的基本类型。
当这些操作符(~和<<)用在 small integer类型(unsigned char 或 unsigned short )时,运算之前要先进行整数提升,结果可能包含并非预期的高端数据位。以下位操作的结果不需要进行强制转换:
1. 结果立即赋值给一个与此操作数具有相同基本类型的对象。 A、B违反
2. 结果作为函数参数,且参数的基本类型应该与操作数一样。
3. 结果作为函数返回值,且函数返回值的基本类型应该与操作数一样。
9. 下列关于++和--运算符的使用,不违反规则的是 C
A mc2_b = mc2_c++; B mc2_a =++mc23_b + mc2_c--;
C mc2_b++;
D
if ( mc2_a++ > 3U )
{
use_uint16 ( mc_a );
}
解析:
规则12.13:在一个表达式中,自增(++ )和自减(- - )运算符不应同其他运算符混合在一起;A,B,D明显违反此规则。
10. 以下if语句中,哪项是正确的 C
float32_t mc2_fp1;
uint16_t mc2_var1;
uint16_t mc2_var2;
bool_tmc2_boolean_a;
A
if (mc2_fp1 != 0U )
{
/*
*********/
}
B
if ( mc2_var2 )
{
/*
*********/
}
C
if ( mc2_boolean_a )
{
/*
*********/
}
D
if ( ( mc2_var2 = mc2_var1 ) != 0U )
{
/*
*********/
}
解析:
规则13.2:数的非零检测应该明确给出,除非操作数是有效的布尔类型。B违反此规则;C符合此规则;
规则10.2:整型和浮点型之间没有隐式转换。A违反此规则;
13.1规则:赋值运算符不能使用在产生布尔值的表达式上。D违反此规则;
11. 判断以下规则描述中正确的是 D
A 函数的定义虽然不得带可变参数的数量,但是可以使用stadarg.h、va_arg、va_start和va_end;
B 函数虽然不能直接调用自身,但是可以间接调用自身;
C 在函数的原型声明和定义中应该为所有参数给出标识符且类型应该匹配,但是给出的标识符可以是不一样的;
D 不带参数的函数应当声明和定义为具有void 类型的参数
解析:
规则16.1:函数定义不得带有可变阐述;这排除了stadarg.h、va_arg、va_start和va_end的使用;A违反此规则;
规则16.2:函数不能调用自身,不管是直接还是间接;B违反此规则;
规则16.3:函数的声明和定义中使用的标识符应该一致。C违反此规则;
D符合规则16.5;
12. 判断以下规则描述中正确的是 C
A C 的宏只能扩展为用大括号括起来的初始化、常量、小括号括起来的表达式、 类型限定符、存储类标识符、类型重定义或do-while-zero 结构。
B 宏不能在块中进行#define和#undef ,但是能使用#define和 #undef
C 函数的使用优先于函数宏,且函数宏的调用不能缺少参数
D 任何预处理指令中所有宏标识符在使用前都应先定义
解析:
规则19.4:C 的宏只能扩展为用大括号括起来的初始化、常量、小括号括起来的表达式、类型限定符、存储类标识符或do-while-zero 结构;A违反此规则;
规则19.6:不要使用#undef。B违反此规则;
C符合规则19.7和19.8;
规则19.11:预处理指令中所有宏标识符在使用前都应先定义,除了#ifdef和#ifndef指令以及defined()操作符;D违反此规则;
13. 判断以下规则描述中正确的是 C
A defined 预处理操作符只能使用三种标准形式之一。
B 应该采取防范措施以允许一个头文件的内容被包含两次。
C 所有的#else 、#elif和#endif 预处理指令应该同与它们相关的#if或 #ifdef 指令放在相同的文件中。
D 在定义函数宏时,每个参数实例都应该以小括号括起来,除非他们作为&或*的操作数
解析:
规则19.14:defined 预处理操作符只能使用二种标准形式之一。A违反此规则;
规则19.15:应该采取防范措施以避免一个头文件的内容被包含两次。B违反此规则;
C符合规则19.17;
规则19.10:在定义函数宏时,每个参数实例都应该以小括号括起来,除非他们作为3或##的操作数。D违反此规则
14. 判断以下规则描述中正确的是 A
A 传递给库函数的值必须检查其有效性。
B不能使用动态堆的内存分配,只是排除了malloc和free的使用。
C 不应使用库
D虽然不允许使用goto,但是可以使用setjmp 宏和longjmp 函数
解析:
A符合规则20.3。
规则20.4:不要使用动态的内存分配。这排除了alloc,malloc,free和realloc的使用。违反此规则;
规则20.6:不要使用库函数
规则20.7:不要使用setjmp宏和longjmp函数。D违反此规则;
15. 判断以下规则描述中正确的是 A
A 在产品代码中不应使用输入/输出库
B 不应使用库
C 不应使用库
D 在产品代码中不应使用
解析:
A符合规则20.9;
规则20.10:不应使用库
规则20.11:不应使用库
MISRA-C对D的描述没用参考哦意见。所以D是不符合MISRA-C的。
16. 考虑汇编语言的使用,请从下列选项中选择汇编语言的三种封装形式 1 、 2 、 3
1汇编函数、2C函数、3宏、4内联函数、5#pragma指令
解析:
规则2.1的规则解析中所描述。
17. 具有 1 作用域的标识符不应使用与具有 2 作用域的标识符相同的名称,这会隐藏 2 标识符。
1内部、2外部
解析:
规则5.2的正文所描述。
18. 具有外部连接的对象和函数应该在唯一的 6 文件中声明且使用 2 存储类区分符,在 5 文件中定义;具有内部链接的函数和对象应该在5 文件中声明且使用 1 存储类区分符,在 5 文件中定义; 6 文件中不应有对象或函数的定义。
1static 、2extern 、3typedef 、4register 、5源 、6头
解析:
规则8.9:具有外部链接的标识符应该具有准确的外部定义。一从声明和定义所在文件考虑,二从存储类标识符考虑使用extern。
规则8.11:static存储类标识符为具有内部链接的对象和函数定义和声明。
规则8.8:外部对象或函数应该声明在唯一的文件中。
规则8.5:头文件中不得有对象或函数的定义;
19. 函数的每个参数类型和函数的返回类型在 1 和 2 中必须是等同的
1声明 、2定义 、3调用 、4重载
解析:
规则8.3的正文所描述。
20. 在枚举列表中,“= ”不能显式用于除 1 元素之外的元素上,除非 4 元素都是显式初始化的。
1 首 2尾 3中间 4所有
解析:
规则9.3的正文所描述。
21. 转换不能发生在函数指针和其他除了 1 之外的任何类型之间。
1整型、 2字符型 、3浮点型 、4其他对象指针、 5void指针
解析:
规则11.1的正文所描述。
22. 转换不能发生在对象指针和其他任何类型之间,除非他们是1,4, 5
1整型、 2字符型 、3浮点型 、4其他对象指针 、5 void指针、 6函数指针
解析:
规则11.2的正文所描述。
23. 逻辑运算符&&或 ||的 2 不能包含副作用。逻辑运算符&&或 ||的操作数应该是primary-expressions,其中primary-expressions或是4 ,或是 5 ,或是 6 。
1左操作数 2右操作数 3操作数 4单一标识符5常量 6小括号括起来的表达式 7函数调用 8复杂表达式
解析:规则12.5的正文和规则解析中所描述。
24. 逻辑运算符( 1 、 2 和 3 )的操作数应该是有效的布尔数。有效布尔数的表达式不应该作为除( 1 、 2 、 3 、 6 , 7 , 8 和 9 )之外操作符的操作数。
1&&、 2||、 3!、 4>=、 5<=、 6==、 7?:、8=、9!=、
解析:
规则12.6的正文所描述。
25. 5 运算符不能用在基本类型无符号的表达式上;不要使用 6 运算符。
1二元加 2二元减 3二元乘 4二元除 5一元减 6逗号 7分号 8句号
解析:
规则12.9和规则12.10的正文所描述。
26. 阅读以下代码段,判断哪些违反了规则 2 4
#include"mc2_types.h" 1
#include"mc2_header.h"
static voidmc2_fn1 ( void );/*注释/*1*/ 2
static void mc2_fn2( void );
/* 注释2. */ 3
void mc2_fun (void )
{
use_int32 ( 0 ); // 注释3 4
}
解析:
规则2.2:源代码应该使用/*….*/类型的注释,这排除了//这样的C99类型的注释。4违反
规则2.3:字符序列/*不应该出现在注释中。2违反
27. 阅读以下代码段,判断哪些违反了规则 2 3 4
void mc2_0204 (void )
{
/* 注释&注释 */ 1
/* 2
use_int32 ( 0 ); 3
*/ 4
use_int32 ( 1 );
}
解析:
规则2.4:代码段不应该被注释掉。2、3、4违反
28. 阅读以下代码段,判断哪些违反了规则 3 4
use_char ( '\a' ); 1
use_char ( '\b' ); 2
use_char ( '\c' ); 3
use_char ( '\d' ); 4
解析:
规则4.1:只能使用ISO C标准中定义的转义序列。3、4使用的非标准转义序列。
29. 阅读以下代码段,对于基本的char类型,判断哪些违反了规则 3 4
char character_value1 = 'a'; 1
char character_value2 = 'b'; 2
char character_value3 = character_value1 + character_value12; 3
if ( character_value1 > 0 ) 4
{
character_value1 = '1'; 5
}
解析:
规则6.1单纯的char类型应该只用做储存和使用字符值。3、4违反此规则。
30. 阅读以下代码段,对于位域的使用,判断哪些违反了规则23 4
struct n_bitfield64
{
unsigned int bf_int:1; 1
char bf_char:6; 2
short bf_short: 5; 3
unsigned char bf_unsigned_char: 3; 4
};
解析:
规则6.4:位域只能被定义为unsigned int和signed int类型。2、3、4违反此规则。
31. 关于隐式转换,请判断下列哪些规则是正确的1 2 3 4 7 8 9
有符号和无符号之间没有隐式转换 1
整型和浮点类型之间没有隐式转换 2
没有从宽类型向窄类型的隐式转换 3
Switch控制表达式中case标签没有隐式转换 4
if控制表达式中判定表达式没有隐式转换 5
for控制表达式中判定表达式没有隐式转换 6
函数参数没有隐式转换 7
函数的返回表达式没有隐式转换 8
复杂表达式没有隐式转换 9
解析:
规则10.1和10.2的规则解析所描述。
32. 关于强制转换,其中s8r是8位有符号整型、s32r、s32a、s32b是32位有符号整型、s64r是64位有符号整型、f32r是32位浮点型、f64a、f64b是64位浮点型。请判断下列错误的选项 2 4
s8r = ( int8_t ) ( s32a + s32b ); 1
s8r = ( int8_t ) ( f64a + f64b ); 2
s32r = ( int32_t )( s32a + s32b ); 3
s64r = ( int64_t )( s32a + s32b ); 4
f32r = ( float32_t) ( f64a + f64b ) 5
解析:
规则10.3:整型复杂表达式只能强制转换到更窄或相同大小的类型且与表达式的基本类型相同的符号。1、4违反此规则。
规则10.4:浮点类型复杂表达式的值只能强制转换到更窄或相同大小的浮点类型。2违反此规则。
33. 阅读下列代码段,找出违反规则的代码行 3 7 8 9 10
{
uint16_t *pi;
uint16_t * *ppi;
constuint16_t cuint16_1105 = get_uint16 ();
volatileuint16_t vuint16_1105 = get_uint16 ();
uint16_t *const cpi = get_uint16_ptr ( );
constuint16_t * pci = &cuint16_1105; 1
constuint16_t * * ppci = &pci; 2
constuint16_6 * * * pppci =&ppci 3
uint16_t *const * pcpi = &cpi; 4
volatileuint16_t * pvi =&vuint16_1105; 5
pi =cpi; 6
pi = ( uint16_t * )pci; 7
pi = ( uint16_t * )pvi; 8
ppi = (uint16_t * * )pcpi; 9
ppi = (uint16_t * * )ppci; 10
}
解析:
规则17.5:对象声明所包含的间接指针不得多于2级。3违反此规则
规则11.5:如果指针所指向的类型带有const或volatile限定符,那么移出限定符的强制转换是不允许的。7移出了pci指向对象的const限定符、8移出了pvi指向对象的volatile限定符、9移出了pcpi所指向对象的const限定符、10移出了pvpi所指向对象的volatile限定符。
34. 请指出下列代码段中存在问题的语句 4
{
uint16_t mc2_var1;
uint16_t mc2_var2;
for ( mc2_var2 = 1U; 1
( mc2_var2 < 22U ) && (mc2_var1 != 8U ); 2
mc2_var2++ ) 3
{
mc2_var2 = mc2_var2 + mc2_var1; 4
mc2_var1 = get_uint16 ( ); 5
}
}
解析:
规则13.6:for循环中用于迭代计数的数值变量不应在循环体中修改。4违反此规则。