const数组指针的正确性?

Lun*_*din 16 c const-correctness

有人提出一个论点,说在现代C中,我们应该总是通过数组指针将数组传递给函数,因为数组指针具有强类型.例:

void func (size_t n, int (*arr)[n]);
...

int array [3];
func(3, &array);
Run Code Online (Sandbox Code Playgroud)

这听起来像防止各种类型相关和数组越界错误可能是一个好主意.但后来我发现我不知道如何将const正确性应用于此.

如果我这样做void func (size_t n, const int (*arr)[n])那么它是正确的.但是由于指针类型不兼容,我无法再传递数组.int (*)[3]对比const int (*)[3].限定符属于指向的数据,而不属于指针本身.

调用者中的显式强制转换将破坏增加类型安全性的整个想法.

如何将const正确性应用于作为参数传递的数组指针?它可能吗?


编辑

就像信息一样,有人说通过像这样的指针传递数组的想法可能源于MISRA C++:2008 5-2-12.例如,请参阅PRQA的高完整性C++标准.

hac*_*cks 5

C标准表示(第6.7.3 / 9节):

如果数组类型的规范包括任何类型限定符,则元素类型是合格的,而不是数组类型。[...]

因此,在的情况下const int (*arr)[n]const应用于数组的元素而不是数组arr本身。arr在将类型指针的参数传递给int的array [n]时,其类型为const int的array [n]的指针。两种类型都不兼容。

如何将const正确性应用于作为参数传递的数组指针?有可能吗?

这是不可能的。不使用显式强制转换就无法在标准C中执行此操作。

但是,GCC允许将此作为扩展

在GNU C中,指向带有限定符的数组的指针的工作方式类似于指向其他限定类型的指针。例如,type的值int (*)[5]可用于初始化type的变量const int (*)[5]这些类型在ISO C中不兼容,因为const限定符正式附加到数组的元素类型,而不是数组本身

 extern void
 transpose (int N, int M, double out[M][N], const double in[N][M]);
 double x[3][2];
 double y[2][3];
 ...
 transpose(3, 2, y, x); 
Run Code Online (Sandbox Code Playgroud)

进一步阅读:在C&C ++中使用const限定符指向数组的指针


M.M*_*M.M 5

除了演员之外没有办法做到这一点.这是以这种方式传递数组的想法的重大缺点.

这是一个类似的线程,其中C规则与C++规则进行比较.我们可以从这个比较中得出结论,C规则设计得不是很好,因为你的用例是有效的,但C不允许隐式转换.另一个这样的例子是转换T **T const * const *; 这是安全的,但不允许C.

请注意,由于n不是常量表达式,因此int n, int (*arr)[n]与之相比没有任何添加的类型安全性 int n, int *arr.你仍然知道长度(n),它仍然是无限制的未定义行为来访问越界,而静默未定义的行为来传递一个实际上不是长度的数组n.

在传递非VLA数组的情况下,当编译器必须报告是否将指针传递给错误长度的数组时,此技术具有更多价值.

  • @Leushenko C11 6.7.6.2/6 表示,如果与 `int (*arr)[n]` 对应的参数不精确是 `int[n]` 类型数组的地址,则这是未定义的行为。在 `int (*arr)[static n]` 中,`static` 没有任何作用。您将这种情况与参数声明“int v[n]”与“int v[static n]”混淆了(您的分析是正确的)。 (2认同)