3

Is this program legal C? If so, please support your claim (either way) with references to one of the language standards.

void f(char *p) {
    char *q = p - 1;
    (void)( q < p );
};

int main(void) {
    char arr[] = "Hello";
    f( arr );
}

In particular, I'm interested in whether the q < p comparison is legal or not.

Frerich Raabe
  • 90,689
  • 19
  • 115
  • 207
  • 1
    The behaviour of `p - 1` is already undefined. Can you rephrase your question in a way that avoids that problem? –  Jul 18 '13 at 08:44
  • @hvd: Well I asked whether the program is legal. If you think it's not, it would be much appreciated if you could post an answer together with references to one of the language standards to support your opinion. If it turns out to be invalid for *multiple* reasons, that's even more interesting. :-) – Frerich Raabe Jul 18 '13 at 08:45
  • Some good explanation can be seen here: http://stackoverflow.com/questions/17584416/c-compare-pointers – devnull Jul 18 '13 at 08:48
  • It's part of 6.5.6 where the `-` operator is described: "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." I posted it as a comment because it doesn't answer the question in your summary. –  Jul 18 '13 at 08:49
  • 2
    @FrerichRaabe: just as one scenario that illustrates why this is undefined - consider a case where an array is allocated at the start of a memory segment deemed large enough for the non-segment-register part of the address to span the elements plus an end address: in that situation, a pointer that you think of as "before" the array may actually have wrapped around (it's unsigned) to the end of the segment, so even without dereferencing the pointer you've got issues with numeric comparison. There are other potential problems on some architectures too - that's just illustrative. – Tony Delroy Jul 18 '13 at 08:57
  • 1
    A remark to both 'replies': the OP was particularly interested if 'q

    – user1666959 Jul 18 '13 at 09:09
  • @user1666959: Yeah, I noticed that myself by now (I was about to write a reply to @hvd until I realised that unfortunately I cannot reason about `f` in isolation :-/). I see that Kerrek SB actually highlighted this aspect, but unfortunately he decided to delete his answer so I cannot upvote it anymore. – Frerich Raabe Jul 18 '13 at 09:12
  • The cheeky answer is: `main` should `return` an `int`, so the behavior is undefined ;) – Fred Foo Jul 18 '13 at 10:43
  • @larsmans: Drat, you're right. I was wearing the C++ hat I guess (AFAIK the `return` is optional in `main`). – Frerich Raabe Jul 18 '13 at 10:51

3 Answers3

4

No, it isn't. Using a pointer which doesn't point to an element of the array or one past its end (i. e. which isn't in the range [&arr[0], &arr[size]]) invokes undefined behavior.

C11 Standard, 6.5.6.8 ("Additive Operators"):

If both the pointer operand and the result [of P + N] 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.

(emphasis mine)

3

No, this is not legal. A pointer must either point into an array, or one past the end of it, or be null.

ISO C11, Appendix J.2 "Undefined behavior", says behavior is undefined when:

Addition or subtraction of a pointer into, or just beyond, an array object and an integer type produces a result that does not point into, or just beyond, the same array object (6.5.6).

This is the case in the line

char *q = p - 1;

when p == &arr[0], and a single line having UB causes the whole program to have UB. Note that you don't have to compare the pointer or dereference it or anything. The subtraction is enough.

Fred Foo
  • 355,277
  • 75
  • 744
  • 836
-1

I don't know about legal but it sure does not make sense. p points to the array, which means holds the address of the array. q points to one address block before the array. Whenever you compare them you'll be comparing the address of two sequential address blocks. The result will always be true, since you are basically comparing p and p-1

lulijeta
  • 900
  • 1
  • 9
  • 19
  • -1; the result need not be true, because the behavior is undefined. In particular, in situations involving segmented memory, the pointer subtraction can do funny things. See Tony D's comment under the question. – Fred Foo Jul 18 '13 at 10:40
  • Of course you are right. When I think of segmented memory it makes a lot of sense. Thank you sir! – lulijeta Jul 18 '13 at 11:00