C 中的常量数组类型,标准中的缺陷?

发布于 2024-07-09 08:23:30 字数 1094 浏览 5 评论 0原文

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]。 这意味着如果给定适当的标志(GCC 的 -Wcast-qual),编译器将正确地抱怨。 在 C 中无法表示 const 数组类型,但这种转换非常有用且“正确”。 -Wcast-qual 标志对于识别数组参数的滥用很有用,但误报阻碍了它的使用。 请注意,与 ap[i*n+j] 相比,索引 a[i][j] 更具可读性,并且对于许多编译器而言,可以生成更好的机器代码,因为前者允许将一些整数算术从内部循环中提升出来,并进行较少的分析。

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

Paragraph 6.7.3.8 of the C99 spec states

If the specification of an array type includes any type qualifiers, the element type is so-qualified, not the array type. If the specification of a function type includes any type qualifiers, the behavior is undefined.

In the rationale (logical page 87, physical page 94), an example of casting a flat pointer to a (variable length) array pointer is given.

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

Certainly if the array ap is not modified within the function, it should be marked const, however the cast in

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

does not preserve the const qualifier since (per 6.7.3.8) it applies to the elements of the target instead of the target itself, which has array type double[n]. This means that compilers will rightly complain if given the appropriate flags (-Wcast-qual for GCC). There is no way to denote a const array type in C, but this cast is very useful and "correct". The -Wcast-qual flag is useful for identifying misuse of array parameters, but the false positives discourage its use. Note that indexing a[i][j] is both more readable and, with many compilers, produces better machine code than ap[i*n+j] since the former allows some integer arithmetic to be hoisted out of inner loops with less analysis.

Should compilers just treat this as a special case, effectively lifting qualifiers from the elements to the array type to determine whether a given cast removes qualifiers or should the spec be amended? Assignment is not defined for array types, so would it hurt for qualifiers to always apply to the array type rather than just the elements, in contrast to 6.7.3.8?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

避讳 2024-07-16 08:23:30

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

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

This is a known issue that has been discussed several times over the last 10 years at comp.std.c. The bottom line is that the specific case you presented is not currently legal in Standard C; you need to either remove the qualifier or refrain from using a pointer to an array to refer to the qualified elements in the array.

If you think you have a good idea to overcome the issue, you can post it to news:comp.std.c for discussion. If others agree that it is a good idea, you or someone else can file a defect report to have the behavior changed (there are several committee members that frequent comp.std.c so feedback from the people who would potentially be reviewing the DR would be useful to have prior to filing it). I think there may be some issues with your proposal to have qualifiers affect the array itself, but I'd have to give it some more thought.

你与清晨阳光 2024-07-16 08:23:30

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

带有 -Wcast-qual 的 gcc 不会抱怨这一点:

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 之间的含义也略有不同,但至少你得到了预期的效果。

Possible workaround for the C programmer (but not the compiler designer):

gcc with -Wcast-qual does not complain about this:

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]);
       /* ... */
    }
}

Even if it's not very elegant. The trailing array member a also has a slightly different meaning between C89 and C99, but at least you get the intended effect.

許願樹丅啲祈禱 2024-07-16 08:23:30

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

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

double *const ap 是指向 double 的常量指针;

const double *const ap 是指向常量 double 的常量指针;

所以我相信可以做你所要求的事情,尽管我已经很多年没有尝试过这个了——你使用的 gcc 选项在我上次这样做时不可用!

编辑:这个答案对于这个问题来说是不正确的 - 我将其保留以保留下面的评论,这为凡人(或生锈的 C 开发人员......)澄清了问题

The situation is awkward with pointers (ie, arrays), but here's my recollection of the details:

const double *ap is a pointer to a constant double;

double *const ap is a constant pointer to a double;

const double *const ap is a constant pointer to a constant double;

So I believe it is possible to do what you're asking, although I've not tried this in years -- the gcc option you're using wasn't available the last time I did this!

EDIT: This answer is not correct for the question - I'm leaving it to preserve the comments below, which clarify the problem for mere mortals (or rusty C developers...)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文