ISO/ IEC JTC1/SC22/WG14 N901

WG14/N901

C99 Defect Reports

Author: Clive Feather <clive@demon.net>
Date: 1999-10-21


Item 1

Subject: lacuna in pointer arithmetic


Problem
-------

Consider the code extract:

    int v [10];
    int p = (v + 9) + 1;
    int q = v + 10;

The relevant part of 6.5.6 paragraph 8 reads:

    If  the  pointer  operand  points  to  an
    element  of  an array object, and the array is large enough,
    the result points to an element  offset  from  the  original
    element  such  that  the difference of the subscripts of the
    resulting and original array  elements  equals  the  integer
    expression.   In  other words, if the expression P points to
    the i-th element of an array object, the  expressions  (P)+N
    (equivalently,  N+(P))  and  (P)-N (where N has the value n)
    point to, respectively, the i+n-th and  i-n-th  elements  of
    the  array  object,  provided  they exist.  Moreover, if the
    expression P points to the last element of an array  object,
    the expression (P)+1 points one past the last element of the
    array object, and if the expression Q points  one  past  the
    last element of an array object, the expression (Q)-1 points
    to the last element  of  the  array  object.   If  both  the
    pointer operand and the result point to elements of the same
    array object, or one past the  last  element  of  the  array
    object,  the  evaluation  shall  not  produce  an  overflow;
    otherwise, the behavior is undefined.

There is a problem with this wording in that it defines arithmetic
of pointers within the array object properly, but it only defines
arithmetic to "one past the end" when the pointer was previously to
the last object. In other words, the initialization of p is correct
because (v + 9) points to the last element of an array, but the
initialization of q is not because the "i+n-th" element does not
exist.

It is clear that these constructs are supposed to work, and that the
relevant wording just needs to be adjusted.


Suggested Technical Corrigendum
-------------------------------

Change the cited text to:

    If the pointer operand points to an element of an array object
    or to one past the last element of the array object, and the
    the array is large enough, the result points to an element, or
    to the location one past the last element, offset from the
    original element such that the difference of the subscripts of the
    resulting and original array elements equals the integer
    expression. In other words, if the expression P points to
    the i-th element of an array object with k elements, or to one
    past the last element (in which case i equals k), then the
    expressions (P)+N and N+(P), (where N has the value n which may
    be positive, zero, or negative) both point to the i+n-th elements
    of the array object, provided it exists, or if i+n equals k, to
    one past the last element of the array object. If both the
    pointer operand and the result point to elements of the same
    array object, or one past the  last  element  of  the  array
    object (that is, both i and i+n lie between 0 and k inclusive),
    the evaluation shall not produce an overflow; otherwise, the
    behavior is undefined.

Similarly, change the following text in paragraph 9:

    In  other  words,  if  the
    expressions  P and Q point to, respectively, the i-th and j-
    th elements of an array object, the expression  (P)-(Q)  has
    the  value  i-j provided the value fits in an object of type
    ptrdiff_t.  Moreover, if the expression P points  either  to
    an  element  of an array object or one past the last element
    of an array object, and the expression Q points to the  last
    element of the same array object, the expression ((Q)+1)-(P)
    has the same value as ((Q)-(P))+1 and as -((P)-((Q)+1)), and
    has  the  value zero if the expression P points one past the
    last element of the array object, even though the expression
    (Q)+1 does not point to an element of the array object.88)

to:

    In other  words,  if the expressions  P and Q point to,
    respectively, the i-th and j-th elements of an array object
    with k elements, or to one past the last element (in which
    case i or j, or both, equals k), the expression  (P)-(Q)  has
    the  value  i-j provided the value fits in an object of type
    ptrdiff_t.88)



Item 2

Subject: partially initialized structures


Problem
-------

Consider the code extract:

    struct listheader
    {
        struct item *head;
        struct item *tail;
    };

    // The following is at block scope

    struct listheader h1;
    h1.head = NULL;

    struct listheader h2;
    h2 = h1;

The value of h1.tail is indeterminate throughout, but provided that
the code never accesses it this is not a problem. However, if it holds
a trap representation, the assignment to h2 involves assigning a trap
representation, which is undefined behaviour.

There are two possible resolutions:

(1) Say that the code is defined. Any implementation that uses
memberwise copying of structures now has to explicitly disable
detection of trap values.

(2) Say that the code is undefined. This is going to surprise a number
of people.