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.