C中的常量数组类型,标准缺陷?
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
for GCC),编译器会正确地抱怨。 没有办法在C中表示const
数组类型,但这种强制转换非常有用并且“正确”。 -Wcast-qual
标志对于识别数组参数的误用非常有用,但误报不鼓励使用它。 请注意,索引a[i][j]
更具可读性,并且对于许多编译器而言,产生的机器代码比ap[i*n+j]
更好,因为前者允许从内循环中提取一些整数算术,而分析更少。
编译器是否应将此视为一种特殊情况,有效地将限定符从元素提升到数组类型以确定给定的强制转换是否删除限定符或是否应修改规范? 没有为数组类型定义赋值,因此限定符总是应用于数组类型而不仅仅是元素,这与6.7.3.8相反?
这是一个已知问题,过去10年在comp.std.c中已多次讨论过。 最重要的是,您提交的具体案例目前在标准C中不合法; 您需要删除限定符或不使用指向数组的指针来引用数组中的限定元素。
如果您认为自己有一个好主意可以克服这个问题,可以将其发布到news:comp.std.c
进行讨论。 如果其他人同意这是一个好主意,那么您或其他人可以提交缺陷报告以改变行为(有几个委员会成员经常使用comp.std.c,因此可能会审查DR的人员的反馈会在提交之前有用)。 我认为你的提议可能存在一些问题,让限定符影响数组本身,但我不得不多考虑一下。
C程序员可能的解决方法(但不是编译器设计者):
gcc与-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; ia[i]); /* ... */ } }
即使它不是很优雅。 尾随数组成员a
在C89和C99之间的含义略有不同,但至少可以获得预期的效果。
指针(即数组)的情况很尴尬,但这是我对细节的回忆:
const double *ap
是一个指向常量double的指针;
double *const ap
是一个指向double的常量指针;
const double *const ap
是一个const double *const ap
的常量指针;
所以我相信你可以做你所要求的,虽然我多年没试过这个 – 你上次使用的gcc
选项在我上次这样做时是不可用的!
编辑:这个问题的答案是不正确的 – 我将其留下来保留下面的评论,这些评论澄清了凡人(或生锈的C开发人员……)的问题