15

C99 规范的第 6.7.3.8 段指出

如果数组类型的规范包括任何类型限定符,则元素类型是限定的,而不是数组类型。如果函数类型的规范包含任何类型限定符,则行为未定义。

基本原理(逻辑页 87,物理页 94)中,给出了将平面指针转换为(可变长度)数组指针的示例。

void g(double *ap, int n)
{
    double (*a)[n] = (double (*)[n]) ap;
    /* ... */ a[1][2] /* ... */
}

当然,如果数组ap没有在函数内修改,它应该被标记为 const,但是在

void g(const double *ap, int n)
{
    const double (*a)[n] = (const double (*)[n]) ap;
    /* ... */
}

不保留const限定符,因为(根据 6.7.3.8)它适用于目标的元素,而不是目标本身,它具有数组类型double[n]。这意味着如果给定适当的标志(-Wcast-qual对于 GCC),编译器会正确地抱怨。没有办法const在 C 中表示数组类型,但这种转换非常有用且“正确”。该-Wcast-qual标志可用于识别数组参数的滥用,但误报会阻止其使用。请注意,索引a[i][j]既更具可读性,而且与许多编译器相比,生成的机器代码比前者更好,ap[i*n+j]因为前者允许将一些整数算术从内部循环中提升出来,而分析更少。

编译器是否应该将其视为一种特殊情况,有效地将限定符从元素提升到数组类型,以确定给定的强制转换是否删除了限定符,或者是否应该修改规范?没有为数组类型定义赋值,因此与 6.7.3.8 相比,限定符总是应用于数组类型而不仅仅是元素会不会有伤害?

4

3 回答 3

6

这是一个已知问题,在过去 10 年中,comp.std.c 已多次讨论过该问题。最重要的是,您提出的具体案例目前在标准 C 中是不合法的;您需要删除限定符或避免使用指向数组的指针来引用数组中的限定元素。

如果您认为自己有解决问题的好主意,可以将其发布到news:comp.std.c讨论。如果其他人同意这是一个好主意,您或其他人可以提交缺陷报告以改变行为(有几个委员会成员经常使用 comp.std.c,因此可能会审查 DR 的人的反馈会在提交之前很有用)。我认为您提出的让限定符影响数组本身的提议可能存在一些问题,但我必须多考虑一下。

于 2008-11-20T14:45:56.880 回答
1

C 程序员(但不是编译器设计者)可能的解决方法:

gcc with-Wcast-qual不会对此抱怨:

void g(const double *ap, int n)
{
    int i;
    struct box 
    {
      double a[n];
    };
    const struct box *s = (const struct box *)ap;

    for (i=0; i<n; ++i)
    {
       doStuffWith(s->a[i]);
       /* ... */
    }
}

即使它不是很优雅。尾随数组成员a在 C89 和 C99 之间的含义也略有不同,但至少你得到了预期的效果。

于 2008-11-20T13:46:49.277 回答
0

指针(即数组)的情况很尴尬,但这是我对细节的回忆:

const double *ap是一个指向双精度常量的指针;

double *const ap是一个指向双精度的常量指针;

const double *const ap是一个指向常量双精度的常量指针;

因此,我相信可以按照您的要求进行操作,尽管我已经很多年没有尝试过了——gcc您使用的选项在我上次执行此操作时不可用!

编辑:这个答案对于这个问题是不正确的——我把它留下来保留下面的评论,这为普通人(或生锈的 C 开发人员......)澄清了这个问题

于 2008-11-20T13:44:13.510 回答