MISRA C 2008规则5-2-7违规:指针类型的对象不得直接或间接转换为不相关的指针类型

在以下示例中:

bool 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); 

  return true;
}

报告了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编程并且不使用任何演员?标准没有说HOW指针转换然后必须完成.

在我的生产代码中,我的问题是在文件读取操作中使用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;
}

根据MISRA应该怎么做?

那么有任何解决方案吗?

编辑:彼得和Q.Q.答案都是正确的,似乎MISRA真的想要做任何事情而没有任何演员阵容,如果项目处于最后阶段很难做到.有两种选择:

1 – 逐一记录MISRA偏差并解释为什么演员阵容好,解释如何测试(Q.Q.建议)

2 – 对于file.read()使用char类型的字节数组,然后在安全地读取文件内容后将字节数组转换为header内容,这必须逐个为每个成员完成,因为如果你将char *转换为int32_t这再次违反规则5-2-7.有时候工作太多了.

最佳答案 MISRA规则的基本原因是将任何指针/地址转换为任何非空指针允许使用该地址,就好像它是一个与实际不同的对象.在这些情况下,编译器会抱怨隐式转换.使用类型转换(或C _cast运算符)实质上会停止编译抱怨并且 – 在很多情况下要计数 – 解除引用该指针会给出未定义的行为.

换句话说,通过强制进行类型转换,您将引入潜在的未定义行为,并关闭编译器警告您可能性的所有可能性. MISRA认为这是一个坏主意….尽管很多程序员认为在编码的简易性方面认为在某些情况下这是一个好主意.

你必须意识到MISRA检查的哲学不像典型程序员那样关心编程的简易性,而是更关心防止未定义(或实现定义或未指定等)行为超过所有检查的情况,并导致代码“in狂野的“可能会造成伤害.

问题是,在您的实际用例中,您依赖于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;
}

您需要做的是更努力地提供将通过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;
}

是的,我意识到这不仅仅是简单地使用类型转换,还允许二进制保存和结构读取.但他们是休息.除了通过MISRA检查程序之外,如果您正确执行此方法,此方法还有其他优点,例如文件格式完全独立于用于构建代码的编译器.您的代码取决于实现定义的数量(结构中成员的布局,sizeof的结果),因此您的代码(如果使用编译器A构建)可能无法读取由编译器B构建的代码生成的文件. MISRA要求的共同主题是减少或消除任何可能对实现定义的数量敏感的行为的代码.

注意:您还将char_t *作为第一个参数传递给std :: istream :: read(),将第二个参数传递给int32_t.两者都是不正确的.实际参数的类型为char *和std :: streamsize(可能是,但不一定是int32_t).

点赞