47

Is it possible, for a pointer variable p, that p<(p+1) is false? Please explain your answer. If yes, under which circumstances can this happen?

I was wondering whether p+1 could overflow and be equal to 0.

E.g. On a 64-bit PC with GCC-4.8 for a C-language program:

int main(void) {
   void *p=(void *)0xFFFFFFFFFFFFFFFF;

   printf("p      :%p\n", p);
   printf("p+1    :%p\n", p+1);
   printf("Result :%d\n", p<p+1);
}

It returns:

p      : 0xffffffffffffffff
p+1    : (nil)
Result : 0

So I believe it is possible for this case. For an invalid pointer location it can happen. This is the only solution I can think of. Are there others?

Note: No assumptions are made. Consider any compiler/platform/architecture/OS where there is a chance that this can happen or not.

bdesham
  • 15,430
  • 13
  • 79
  • 123
akarapatis
  • 852
  • 8
  • 18
  • 1
    Fundamentally this is an interesting question. But what are your thoughts on it? – Bathsheba Dec 03 '14 at 13:32
  • 9
    @Borgleader No, it is not! I got asked this question at an interview questionnaire. I have googled for days and didn't find a clear answer. I believe it is a fair question to be on stackoverflow – akarapatis Dec 03 '14 at 13:34
  • 1
    I'm getting the impression that the *intended* answer deals with things like `(char*)-1`, for which an implementation is *likely* to let `p<(p+1)` evaluate to false, but that pointer constant is invalid in both C and in C++. –  Dec 03 '14 at 13:35
  • 2
    @akarapatis It's not a fair question the way you're asking it now, in my opinion, but it could be re-worded into a fair question. –  Dec 03 '14 at 13:36
  • @Bathsheba I edited my question. These are my thoughts – akarapatis Dec 03 '14 at 13:41
  • @hvd Tell me then how would you ask it then? Note: I edited the body of my question – akarapatis Dec 03 '14 at 13:43
  • @akarapatis Yes, that edit (which, to be clear to others, wasn't there yet when I posted my comment) makes it look like a decent question to me. –  Dec 03 '14 at 13:45
  • 1
    What's your definition of `<` for pointers? – barak manos Dec 03 '14 at 13:54
  • @barakmanos I am not making any assumptions. That is what I am asking – akarapatis Dec 03 '14 at 13:56
  • I did not suggest that you were making any assumptions. I simply asked, how do you define whether or not pointer `p1` is smaller than pointer `p2`? – barak manos Dec 03 '14 at 13:59
  • @barakmanos Arithmetically. "1<2" is true – akarapatis Dec 03 '14 at 14:03
  • 1
    So if you consider them as integers, then what is the question really? `x – barak manos Dec 03 '14 at 14:06
  • 9
    @barakmanos The question is quite clear, and it is about what the language guarantees you. The language has clear definitions as for what + and < mean for a pointer variable, it's quite irrelevant what akarapatis definition of < for a pointer is, or whether you consider pointers as integers. – nos Dec 03 '14 at 14:30
  • @akarapatis: are you asking when this _can_ happen, or when this _will_ happen? If it's the former, the answer is "always", as arithmetic appears to be undefined for `void` pointers. – Daan Dec 03 '14 at 15:42
  • 2
    In C and C++, if `p` points to a valid object, then `p

    – Iwillnotexist Idonotexist Dec 03 '14 at 18:27
  • @Barak - For your question, *"What's your definition of < for pointers"*, see [Pointer comparisons in C. Are they signed or unsigned?](https://stackoverflow.com/q/6702161/608639) – jww Dec 18 '17 at 00:39

5 Answers5

44

Is it possible, for a pointer variable p, that p<(p+1) is false?

If p points to a valid object (that is, one created according to the C++ object model) of the correct type, then no. p+1 will point to the memory location after that object, and will always compare greater than p.

Otherwise, the behaviour of both the arithmetic and the comparison are undefined, so the result could be true, false, or a suffusion of yellow.

If yes, under which circumstances can this happen?

It might, or might not, happen with

p = reinterpret_cast<char*>(numeric_limits<uintptr_t>::max);

If pointer arithmetic works like unsigned integer arithmetic, then this might cause a numeric overflow such that p+1 has the value zero, and compares less than p. Or it might do something else.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
  • Comments are not for extended discussion; this conversation has been [moved to chat](http://chat.stackoverflow.com/rooms/66126/discussion-on-answer-by-mike-seymour-pointerp-arithmetic-could-pp1-be-fal). – Taryn Dec 03 '14 at 14:11
  • 7
    "Suffusion of yellow" only applies for values > 4. – Mike G Dec 03 '14 at 22:05
  • I would draw attention to "undefined." In the specification, it explicitly calls out that the result of any pointer arithmetic that would result in an overflow is undefined behavior. Undefined behavior is the spec's nastiest "anything goes" answer. `p<(p+1)` cases are valid... as are cases where it just crashes outright when you try. – Cort Ammon Dec 04 '14 at 04:13
  • @SteveJessop: Indeed. That's all in the discussion which was moved to chat. – Mike Seymour Dec 04 '14 at 14:53
  • @Mike: ah, I didn't read that because it's moved to chat. I think what I said is a worthwhile addition/clarification to your answer, but obv if you don't want to make it that's entirely up to you, I won't edit. – Steve Jessop Dec 04 '14 at 14:54
  • Can't it be implementation specific? Couldn't addressing be inverted in extreme cases? – Kubuxu Dec 08 '14 at 14:24
  • @Kubuxu: Not if the pointer is to an object created by the program, and the compiler follows the rules for pointer arithmetic and comparison specified by the standard. (See the [discussion](http://chat.stackoverflow.com/rooms/66126/) for the gory details.) – Mike Seymour Dec 08 '14 at 14:51
  • @bluefeet - You're doing important work. Moving bits from here to there, to and fro. It's a thing that really matters. Really. Good job. – Wayne Dec 09 '14 at 22:06
  • In the "otherwise" case, the arithmetic is undefined; comparison is merely unspecified. – T.C. Feb 15 '15 at 13:36
  • @T.C.: No, the comparison uses an invalid pointer (the result of undefined arithmetic), so is also undefined behaviour. – Mike Seymour Feb 15 '15 at 13:46
  • True, undefinedness propagates, and it doesn't even make much sense to discuss the comparison when you are already in UB-land from the arithmetic. My point was that comparisons on valid pointers don't give UB even when the pointers are otherwise unrelated (despite some claims to the contrary). – T.C. Feb 15 '15 at 13:48
  • @T.C.: OK, but that point isn't relevant to this question. This question has already had one tedious off-topic discussion of the precise nature of UB moved to chat; there's no need for another. – Mike Seymour Feb 15 '15 at 13:51
14

What if I'm programming on DOS, and I have a far pointer (one composed of a segment and an offset), and it's pointing to the last address in the segment, and I add one to it, and the pointer wraps around? It looks like when you're comparing them, you normalize the pointers, so the second pointer p+1 would be less than p.

This is a stab in the dark though, I don't have a DOS C compiler handy to test on.

dsolimano
  • 8,870
  • 3
  • 48
  • 63
  • 1
    Segmentation is irrelevant -- an unsegmented pointer can wrap around too. – TonyK Dec 03 '14 at 13:49
  • 3
    Not entirely. Depending on the memory model, you can have objects which exceed segmentation boundaries. In the `huge` memory model, incrementing a pointer to the last address in a segment is valid because arrays there can cross segment boundaries. That means the compiler must check for overflow and adjust the segment part accordingly. With unsegmented pointers, you can't wrap around across `nullptr`. – MSalters Dec 03 '14 at 14:38
10

It could happen with an invalid pointer.

But if the pointer points to a valid memory location, on many operating systems (e.g. Linux), it practically never happens (at least if the sizeof(*p) is not too big), because in practice the first and last pages of the address space are never mapped (but you could force a mapping with mmap & MAP_FIXED).

For freestanding implementations (i.e. inside a kernel, or on some microcontroller), things are different, and implementation specific (perhaps might be undefined behavior, or unspecified behavior).

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
10

Very simple: It cannot happen if there is no undefined behaviour involved. It can happen very easily in the presence of undefined behaviour. For details, read a copy of the C Standard or C++ Standard.

As a result, a conforming compiler is allowed to not evaluate the < operator at all and use 1 or true as the result instead. The same is true for arithmetic with signed integers (but not for unsigned integers, where it is possible for entirely legal code to have x > x+1).

Your example code isn't even C or C++, so you seem to have used the compiler in a mode where it isn't a standard conforming C or C++ compiler.

gnasher729
  • 51,477
  • 5
  • 75
  • 98
  • In general my point under which circumstances can this happen. As @Basile Starynkevitch mentioned in his answer, for a freestanding implementation there is a possibility this can happen. I understand that for code compiled with a conforming compiler on a OS there is no chance. I know my "example" was over-simplified and invalid but through the discussion I hopped to get more insight – akarapatis Dec 04 '14 at 16:26
3

According to Pointer comparisons in C. Are they signed or unsigned? on Stack Overflow:

You can't legally compare arbitrary pointers in C/C++. The result of such comparison is not defined.

jww
  • 97,681
  • 90
  • 411
  • 885
HappyCactus
  • 1,935
  • 16
  • 24
  • 3
    From the post you mention: "C language (as well as C++) defines pointer comparisons only for pointers that point into the same aggregate (struct or array)" - I believe I am referring to the same pointer. – akarapatis Dec 03 '14 at 15:11
  • 1
    I am not sure: p and p+1 are void *, so they are not referring to an array (as it would if they was char * or anything *). Anyway, you raised an interesting question. – HappyCactus Dec 03 '14 at 15:21
  • @HappyCactus: The question doesn't specify that p is a void * (it does give an example sing a void *p, but the question itself is phrased generically...) – psmears Dec 03 '14 at 17:51