“不要!”是正确的答案,但不幸的是,这不是我需要的答案。
如果我这样做:
size_t array_size = func_that_calc_array_size();
char *foo = new char[array_size];
if (array_size > 42)
foo[42] = 'X';
这完全是合法的,但是我的MISRA C ++代码检查器在foo[42]
上给出了5-0-15错误,它表示“数组索引将是指针算术的唯一形式”。这个问题有actually been asked before,但该问题和答案遗漏了一个关键问题,即文档进一步指出:
数组索引只能应用于定义为数组类型的对象。
如果您查看文档(可通过搜索“ misra c ++ 2008 pdf”找到可疑的盗版副本),则其示例类似于:
void my_fn(uint8_t *p1, uint8_t p2[])
{
p1[5] = 0; // Non-compliant - p1 was not declared as array
p2[5] = 0; // Compliant
}
因此,基本上,代码检查工具将声明与用法匹配。有没有可能将指针转换为数组的方法?
在我们的实际示例中,我们使用的是OpenCV的uchar *cv::Mat::ptr()
,因此我们不能只保留足够大的数组。
答案 0 :(得分:1)
该规则的有效性令人怀疑。在示例中,p1
和p2
具有完全相同的类型:它们都是指针。
如果p2
确实符合规则,那么解决方案是引入一个函数,以便您可以使用function-argument-array-pointer-adjustment。这是一个带有lambda的示例,但是您也可以使用常规函数:
char *foo = new foo[array_size];
if (array_size > 42)
[](char foo[]) {
foo[42] = 'X';
}(foo);
C ++ 20引入了std::span
,这似乎是解决该问题的方法:
std::span foo_span{foo, array_size};
if (array_size > 42)
foo_span[42] = 'X';
这使用下标运算符的类重载,而不是指针下标的重载,因此它似乎符合规则。 std::span
在不违反MISRA的情况下可能无法实现,但是在标准库中还有很多其他事情,因此我怀疑这不是问题。
在我们的实际示例中,我们使用的是OpenCV的
uchar *cv::Mat::ptr()
,因此我们不能只保留足够大的数组。
也许应该遵循规则的精神而不是字母,应该在函数中传递cv::Mat&
而不是char*
。
P.S。我怀疑OpenCV不符合MISRA,因此如果程序必须符合MISRA,那么最好不要依赖它。
答案 1 :(得分:1)
我认为这里的问题根源是char *foo = new char[array_size];
。可以说允许MISRA检查器假定它不是数组,因为所有动态内存分配均被禁止。
您可以尝试查看在编写char array[10]={0}; char* foo = array;
时是否遇到相同的错误,因为这样您就可以将其视为误报工具错误。
该规则的目的和原理是禁止使用*(x + i)
而不是x[i]
的形式。没有其他的。该规则不会阻止在指针操作数上使用[]
。
但是,有几条MISRA规则可以确保所有指针运算都使用指向同一数组的操作数完成,以防止发生未定义的行为。
MISRA-C:2004和MISRA-C ++:2008也有一些奇怪,含糊的要求,即应将函数参数声明为char param[]
而不是char* param
,但是由于这是毫无意义的,因此有关数组样式索引的信息已在MISRA-C:2012中删除。
(实际上,在C或C ++中没有“数组样式索引”之类的东西,请参见Do pointers support "array style indexing"?)