Baj*_*ile 7 c++ pointers misra system-requirements
在以下示例中:
void bad_function()
{
char_t * ptr = 0;
// MISRA doesn't complains here, it allows cast of char* to void* pointer
void* p2 = ptr;
// the following 2 MISRA violations are reported in each of the casts bellow (two per code line)
// (1) Event misra_violation: [Required] MISRA C++-2008 Rule 5-2-7 violation: An object with pointer type shall not be converted to an unrelated pointer type, either directly or indirectly
// (1) Event misra_violation: [Required] MISRA C++-2008 Rule 5-2-8 violation: An object with integer type or pointer to void type shall not be converted to an object with pointer type
ptr = (char_t*) (p2);
ptr = static_cast<char_t*> (p2);
ptr = reinterpret_cast<char_t*> (p2);
}
Run Code Online (Sandbox Code Playgroud)
报告了 MISRA 5-2-8 和 5-2-7 违规行为。
我怎样才能消除这种违规行为?
我需要有 C++ 静态分析经验的人来帮助我。几天来我对这些愚蠢的规则感到头疼。
根据 MISRA C++ 标准(MISRA-Cpp-2008.pdf: 规则 5-2-7(必需)):具有指针类型的对象不得直接或间接转换为不相关的指针类型。
好的,但是我们有很多代码,例如需要将地址转换为char*然后将其与 一起使用std::ifstream,该read(char* buffer, int length)函数需要将地址类型转换为 ( char_t*)。那么,根据 MISRA 人员的说法,如何才能用 C++ 进行编程而不使用任何类型转换呢?标准没有说明必须如何完成指针转换。
在我的生产代码中,我的问题在于使用std::ifstream从预定义数据结构中的文件读取文件的操作:
if (file.read((char_t*)&info, (int32_t)sizeof(INFO)).gcount() != (int32_t)sizeof(INFO)
{
LOG("ERROR: Couldn't read the file info header\n");
res = GENERAL_FAILURE;
}
Run Code Online (Sandbox Code Playgroud)
根据 MISRA 应该如何做?
那么有什么解决办法吗?
编辑:Peter和QQ的答案都是正确的,看来MISRA真的想在没有任何演员的情况下完成所有事情,如果项目处于最后阶段,这是很难做到的。有两种选择:
1 - 逐一记录 MISRA 偏差并解释为什么强制转换是好的,解释这是如何测试的(QQ建议)
2 - 使用 char 类型的字节数组进行 file.read(),然后在安全读取文件内容后将字节数组转换为标题内容,必须对每个成员一一执行此操作,因为如果将 char* 转换为 int32_t再次违反规则 5-2-7。有时工作量太大了。
MISRA 规则的基本原因是,将任何指针/地址转换为任何非空指针都允许使用该地址,就好像它是与实际不同的对象一样。在这些情况下,编译器会抱怨隐式转换。使用类型转换(或 C++_cast运算符)本质上会停止编译抱怨,并且在太多情况下无法计数 - 取消引用该指针会产生未定义的行为。
换句话说,通过强制类型转换,您将引入潜在的未定义行为,并关闭编译器警告您这种可能性的所有可能性。MISRA 认为这是一个坏主意……尽管许多考虑编码简易性的程序员认为在某些情况下这是一个好主意。
您必须认识到,MISRA 检查的理念不像典型的程序员那样关心编程的方便性,而是更关心防止未定义(或实现定义或未指定等)行为通过所有检查并导致代码“在野生”可能会造成伤害。
问题是,在您的实际用例中,您依赖于file.read()正确填充名为 的(大概)数据结构info。
if (file.read((char_t*)&info, (int32_t)sizeof(INFO)).gcount() != (int32_t)sizeof(INFO)
{
LOG("ERROR: Couldn't read the file info header\n");
res = GENERAL_FAILURE;
}
Run Code Online (Sandbox Code Playgroud)
您需要做的是更加努力地提供可通过 MISRA 检查器的有效代码。就像是
std::streamsize size_to_read = whatever();
std::vector<char> buffer(size_to_read);
if (file.read(&buffer[0], size_to_read) == size_to_read)
{
// use some rules to interpret contents of buffer (i.e. a protocol) and populate info
// generally these rules will check that the data is in a valid form
// but not rely on doing any pointer type conversions
}
else
{
LOG("ERROR: Couldn't read the file info header\n");
res = GENERAL_FAILURE;
}
Run Code Online (Sandbox Code Playgroud)
是的,我意识到这比简单地使用类型转换并允许二进制保存和读取结构需要更多的工作。但他们就是休息时间。除了通过 MISRA 检查器之外,如果操作正确,这种方法还有其他优点,例如文件格式完全独立于用于构建代码的编译器。您的代码取决于实现定义的数量(结构中成员的布局、sizeof),因此您的代码(如果使用编译器 A 构建)可能无法读取由编译器 B 构建的代码生成的文件。其中之一MISRA 要求的共同主题是减少或消除任何可能对实现定义的数量敏感的行为的代码。
注意:您还传递char_t *tostd::istream::read()作为第一个参数和 anint32_t作为第二个参数。实际上两者都是不正确的。实际参数的类型为char *and std::streamsize(可以是,但不要求是int32_t)。