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

Converting a pointer to X to an array of X

"Don't!"是正确答案,可惜不是我需要的。

如果我这样做:

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,表示 "Array indexing shall be the only form of pointer arithmetic"。这个问题有,但是问题和答案遗漏了一个关键问题,即文档进一步指出:

Array indexing shall only be applied to objects defined as an array type.

如果您查看文档(可以通过搜索 "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(),所以我们不能只保留一个足够大的数组。

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

如果p2确实符合规则,那么解决办法就是引入一个函数,这样就可以利用function-argument-array-to-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';

这使用了下标运算符的 class 重载,而不是 pointer-subscript,因此看起来符合规则。 std::span 在不违反 MISRA 的情况下可能无法实现,但标准库中的许多其他内容也是如此,所以我怀疑这不是问题。


In our real example, we are using OpenCV's uchar *cv::Mat::ptr(), so we can't just reserve a large-enough array.

也许遵循规则的精神,而不是字母,您应该将 cv::Mat& 传递给函数而不是 char*

P.S。我怀疑 OpenCV 不符合 MISRA,因此如果程序必须符合 MISRA,依赖它可能不是最好的选择。

我认为问题的根源在于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++ 中没有 "array style indexing" 这样的东西,参见