在以下示例中:
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);
}据报告,米斯拉5-2-8和5-2-7违规。
我怎么才能移除这个违规行为?
我需要一个有C++静态分析经验的人来帮助我。几天后我就用这条愚蠢的规则砸我的头了。
根据MISRA C++标准(MISRA-Cpp 2008.pdf:规则5-2-7 (必需):具有指针类型的对象不应直接或间接转换为无关指针类型。
好的,但是我们有很多代码,例如,需要将address转换为char*,然后将其与std::ifstream一起使用,read(char* buffer, int length)函数需要将地址类型转换为(char_t*)。那么,根据米斯拉的说法,一个人怎么能在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;
}根据米斯拉的说法该怎么做?
那么有什么解决办法吗?
编辑: Peter和Q.Q的答案都是正确的,看起来MISRA真的想要做任何事情,而没有任何类型的转换,如果项目处于最后阶段,这是很难完成的。A有两种选择:
1-逐个记录MISRA偏差,解释为什么转换正常,解释这是如何测试的(Q.Q.建议)
2-对file.read()使用char类型中的字节数组,然后在安全地读取文件内容后,将字节数组强制转换为标头内容,这必须一个一个地对每个成员执行,因为如果您将char*强制转换为int32_t,则再次违反规则5-2-7。有时候工作太多了。
发布于 2015-12-14 13:11:05
MISRA规则的基本原因是,将任何指针/地址转换为任何非空指针允许使用该地址,就好像它是一个不同于实际的对象一样。在这种情况下,编译器会抱怨隐式转换。使用类型广播(或C++ _cast操作符)实质上停止编译抱怨,并且在太多情况下取消引用该指针会产生未定义的行为。
换句话说,通过强制类型转换,您将引入潜在的未定义行为,并关闭编译器提醒您注意这种可能性的所有可能性。米斯拉认为这是个坏主意..。许多程序员认为在某些情况下这是个好主意,但他们认为这是个好主意。
您必须认识到,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;
}您需要做的是更加努力地提供通过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)。
发布于 2015-12-09 15:30:23
将不相关的指针转换为char*并不是一个好做法。但是,如果有一个大型遗留代码库经常这样做,则可以通过添加特殊注释来抑制规则。
发布于 2015-12-09 15:42:27
fread是一个非常好的文件输入C++函数,它使用了MISRA允许的void*。
它还擅长读取二进制数据,不像fstream那样通过本地化字符转换逻辑处理所有数据(这是iostream上的"facet“,它是可配置的,但标准没有定义任何可移植的方式来实现无操作转换)。
fopen/fclose的C风格在C++程序中是不幸的,因为您可能忘记清理文件。幸运的是,我们有这个std::unique_ptr,它可以将RAII功能添加到任意指针类型中。使用std::unique_ptr<FILE*, decltype(&fclose)>并在C++中具有快速异常安全二进制文件I/O。
注意:一个常见的误解是std::ios::binary给出二进制文件I/O,它没有。它只影响换行符转换和(在某些系统上)文件结束标记处理,但对面驱动字符转换没有影响。
https://stackoverflow.com/questions/34182306
复制相似问题