Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Constant array types in C, flaw in standard?

Tags:

c

standards

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?

like image 504
Jed Avatar asked Nov 20 '08 13:11

Jed


2 Answers

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.

like image 198
Robert Gamble Avatar answered Sep 20 '22 07:09

Robert Gamble


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.

like image 38
finnw Avatar answered Sep 22 '22 07:09

finnw