Question

Is comparing two pointers to different char objects undefined in C?

This is code of memmove from https://github.com/gcc-mirror/gcc/blob/master/libgcc/memmove.c

void *
memmove (void *dest, const void *src, size_t len)
{
  char *d = dest;
  const char *s = src;
  if (d < s)
    while (len--)
      *d++ = *s++;
  else
    {
      char *lasts = s + (len-1);
      char *lastd = d + (len-1);
      while (len--)
        *lastd-- = *lasts--;
    }
  return dest;
}

C11 standard says in 6.5.8. Relational operators:

When two pointers are compared, the result depends on the relative locations in the address space of the objects pointed to. If two pointers to object types both point to the same object, or both point one past the last element of the same array object, they compare equal. If the objects pointed to are members of the same aggregate object, pointers to structure members declared later compare greater than pointers to members declared earlier in the structure, and pointers to array elements with larger subscript values compare greater than pointers to elements of the same array with lower subscript values. All pointers to members of the same union object compare equal. If the expression P points to an element of an array object and the expression Q points to the last element of the same array object, the pointer expression Q+1 compares greater than P. In all other cases, the behavior is undefined.

It looks like the code above compares pointers to two different objects:

  if (d < s)

i.e. the behavior is undefined, is this true? Or comparing pointers to chars are well-defined?

 2  106  2
1 Jan 1970

Solution

 5

Implementations of a standard C library may require that compilers they are paired with define certain behaviors. In other words, a library implementation may state “This library relies on the fact that a compiler supports the relational operators on any two pointers to object types” and may then make use of that in its code.1

The fact that the C standard does not define a behavior does not prohibit a C implementation from defining the behavior and does not prohibit an implementation of the standard C library from requiring it be defined.

i.e. the behavior is undefined, is this true? Or comparing pointers to chars are well-defined?

Something can be both undefined and fully defined.

This is because, in the context of C, undefined is generally used to mean undefined behavior in the sense specified in the C standard. This sense of the word has only one meaning:

behavior, upon use of a nonportable or erroneous program construct or of erroneous data, for which this document imposes no requirements [C 2018 3.4.3 1].

Here are some things this sense of the word “undefined” or the phrase “undefined behavior” does not mean:

  • It does not mean you may not use the construct or the data.

  • It does not mean the C implementation cannot define the behavior.

  • It does not mean you cannot examine and reason about the behavior based on things outside the C standard, such as the operating system, the hardware design, or the laws of physics.

So, a C implementation can define an “undefined” behavior. It is then a behavior undefined by the C standard but defined by the C implementation.

Footnote

1 Library implementations are often poorly documented and may fail to state such requirements explicitly or clearly. Nonetheless, this is the rationale for a library being able to use things that are not defined by the C standard alone.

2024-07-19
Eric Postpischil