将指向X的指针转换为X的数组

时间:2019-06-03 02:10:50

标签: c++ misra qa-c

“不要!”是正确的答案,但不幸的是,这不是我需要的答案。

如果我这样做:

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(),因此我们不能只保留足够大的数组。

2 个答案:

答案 0 :(得分:1)

该规则的有效性令人怀疑。在示例中,p1p2具有完全相同的类型:它们都是指针。

如果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"?