0

Suppose I need a function that checks whether two arbitrary buffers are interleaved*. One straightforward idea that comes to mind would be this:

bool isInterleaved(uint* buf1, // pointer to first buffer
                   uint* buf2, // pointer to second buffer
                   uint len1,  // length of first buffer
                   uint len2,  // length of second buffer
                   uint stride1, // stride length of first buffer
                   uint stride2) // stride length of second buffer
{
    ... // first some sanity checks like (NULL != buf), (0U < len),...

    bool retval = false;
    if ((len1 == len2) && (2U == stride1) && (2U == stride2))
    {
        if ((&buf1[1] == &buf2[0])  ||
            (&buf2[1] == &buf1[0]))
        {
            retval = true;
        }
    }
    return retval;
}

On paper, it looks good enough, quick tests were positive. However, In C and C++, the comparison of pointers to objects is only strictly defined if the pointers point to members of the same object, or elements of the same array.

Does my example - specifically the line with (&buf1[1] == &buf2[0]) and the one after - constitute undefined behavior? If yes, how could I implement a check like this without relying on undefined behavior?


*see edit history for an example of interleaved data or check the wikipedia article on interleaving. It is not 'a wrong word', as a comment suggests.

  • What's the purpose of stride? – Fiddling Bits Jan 22 '20 at 14:38
  • "Interleaved" ?? Do you mean "overlap" ? – Jabberwocky Jan 22 '20 at 14:39
  • 'stride' is the stride length of the buffers, i.e. the location of the n-th element of buffer1 would not be `buffer1[n]` but `buffer1[n * stride1]` – UnbescholtenerBuerger Jan 22 '20 at 14:45
  • 3
    "Interleaved" must be a wrong word. "Overlapping" may be better but that's not really what the code checks. This Q is very unclear. – Support Ukraine Jan 22 '20 at 14:51
  • Note: If they're interleaved then they have to point to the same object. I don't think there's any other way to get interleaved objects. – user253751 Jan 22 '20 at 14:51
  • @UnbescholtenerBuerger please define "interleaved". I you can't do it in English, show us a picture, ask someone else or use translate.google.com – Jabberwocky Jan 22 '20 at 14:53
  • How exactly do you intend to call this function? Your definition of "interleaved" is correct, however in the context of the given function it makes even less sense what it is trying to do. – dbush Jan 22 '20 at 15:24
  • it does make sense in my application, but that's not the point of the question anyways. – UnbescholtenerBuerger Jan 22 '20 at 15:37
  • @UnbescholtenerBuerger The point I was trying to make is that while your code does not exhibit UB, it also does not determine if two buffers are interleaved. Actually, it doesn't even make sense to say two buffers are interleaved, but rather that one buffer contains the interleaved contents of two or more others. What your function does do is check if two buffers *overlap*, specifically whether the start of two buffers differ by 1 array element. That's where the confusion is coming from. – dbush Jan 22 '20 at 17:47
  • Note that while the Standard defines the `==` operators for arbitrary combination of pointers, gcc and clang are both prone to behave nonsensically when using it to compare the address of one object to another which is "just past" an unrelated object that happens to immediately precede it. The problem isn't merely that the comparison might fail to report address equality, but it may cause them to wrongly assume that an access to one of the pointers can't interact with other accesses to the same object. – supercat Jan 23 '20 at 05:07

1 Answers1

2

Does my example constitute undefined behavior?

The code as presented does not have undefined behavior. Pointers can be compared with ==. Even when they point to different objects.

The rule you are referring applies to < > <= and >= operators. Using those operators on "different objects" is undefined behavior. In the draft of the standard semantics of relational operators on pointers can be found in C99 6.5.8p5.

KamilCuk
  • 120,984
  • 8
  • 59
  • 111