Bug in wimp.h

Chris Rutter chris at willow.armlinux.org
Thu Aug 24 12:53:00 BST 2000


On Thu, 24 Aug 2000, David Bryan wrote:

> Yes, I thought Chris was right.  From K&R Second Ed.,
> 
>   The purpose of const is to announce objects that may be placed
>   in read-only memory, and perhaps to increase opportunities for
>   optimization.

Well, in all fairness, `const' being a rather subtle beast, there /is/
a chance that K&R2 is inaccurate w.r.t. ANSI C89.

> I thought that compilers tended not to perform such optimisation,
> because such pointer optimisation can be hard to get right, and
> doesn't yield much improvement.

Yes, absolutely; I think most backends tend to have such tight
restrictions and such boringly standard calling sequences that in
practice, the issue very, very rarely comes up.  (This is a more
considered viewpoint than that which I stated earlier.)

I must admit to being bemused by the great variety of places one can
interpolate `const' into a type expression, and not /actually/ being
entirely sure as to what every single one of them means.  I imagine
that neat command-line tool which produces English expressions from
C type aggregates would help here.

I think that `const TYPE *' == `TYPE const *', and in fact that latter
is more consistent with the `dereference and qualify from the right'
rule, but people have tended to plump for the idiosyncratic former
option.

>   void f1(char *)
>   void f2(const char *)
>   
>   void f3(void)
>   {
>      char ca[32];
>      
>      f1(&ca[16]);
>      ...
>      ca[0] = '\0';
>      f2(ca);
>      /* Can't assume ca[0] == '\0' */
>      ...
>   }

My brain's asleep.  Why is that?  That case is surely identical to:

    void f (const char *k)
    {
      printf("char = %d\n", *k);
    }

    int main ()
    {
      char ca[32];
      *ca = 'a';
      f(ca);
      /* Why can't @ca@ be assumed to be 'a' here? */
    }

The seeming paradox has rather puzzled me: clearly more than /just/ the
pointed-to object are, pragmatically, going to get modified: and thus
how far do the array bounds extend either way?

In the `const' case, you might say `infinitely in either direction' --
however, then you have to apply that bounding to the non-`const' case
/too/: i.e. that function that takes a non-`const' pointer is at
liberty, in the compiler's eyes, to modify /infinitely/ (well,
I think array bounds are limited to `INT_MAX' or somesuch) either side
of it: thus potentially scribbling over `const' types in memory.

It would clearly be silly if in the case of a `const char *', all ANSI
guaranteed you was that /the/ pointed-to object wasn't modified and
not anything either side: that would be a useless guarantee.  Therefore,
I assume that it implies that all valid array points of that object
don't get modified.  Therefore, I assume that applies to non-const,
too.  /Therefore/, what about this case:

    struct file {
      int a;
      unsigned b;
    };

    void b (struct file *f)
    {
      f->a++;
      f[6]->a = 1;
    }

    void a ()
    {
      struct file f[16];
      struct file *g;

      g = &f[6];
      g->a = 9;

      b(f);

      /* Compiler still thinks that @g->a == 9@ -- it doesn't know that
       * it bears any relation to @f@
       */
    }

Now, if ANSI has infinitely-extending array bounds as to what can be
modified based on a passed pointer, @g@ could well be trashed by b(),
/but/ then the compiler has to keep track of the fact that @g@ is a
valid array-indexed offset from @f@, and therefore flush its values
after a call to b().  Obviously you could force this with `volatile',
but that's obviously not the solution.

I ought to find my copy of the Standard, really. :-/

> I have heard that the MetaWare C compiler can perform such
> optimisation.  (And, there's an ARM back end for it.)  Languages
> without explicit pointers are better :-)

Where's that available from?

> Negligible space.  (Most of the object file's bulk is symbol
> tables etc.)

Yup.  Great.

c.




More information about the oslib-user mailing list