Undefined Behavior

Werror sequence-point

Consider this code:

char *reverse(const char *s) {
  size_t len = 0;
  size_t j = 0;
  char *dst;

  while (*(s + len) != '\0')
    ++len;

  dst = malloc(len + 1);

  while (*(s + j) != '\0')
    *(dst + j) = *(s + len - 1 - j++);

  *(dst + len) = '\0';

  return dst;
}

gcc gets angry: “error: operation on ‘j’ may be undefined”.

gcc \
  -std=c99 \
  -g \
  -Wall \
  -Wextra \
  -pedantic \
  -Werror \
  -Wmissing-declarations \
  -fsanitize=address,undefined \
  -fno-common -fno-omit-frame-pointer \
  -DUNITY_SUPPORT_64 \
  -DUNITY_OUTPUT_COLOR \
  test-framework/unity.c \
  ./test_reverse_string.c \
  ./reverse_string_v3.c \
  -o memcheck.out
./reverse_string_v3.c: In function ‘reverse’:
./reverse_string_v3.c:22:35: error: operation on ‘j’ may be undefined [-Werror=sequence-point]
   22 |     *(dst + j) = *(s + len - 1 - j++);
      |                                  ~^~
cc1: all warnings being treated as errors

It so happens that we are using j in between the so called sequence points, and the compiler cannot properly decide if j on the left hand side of the assignment operator has to be evaluated before or after the j++ on the right hand side of the expression.

That use of j++ is simply not allowed in that situation and the fix is to increment j on an expression of its own:

- while (*(s + j) != '\0')
-   *(dst + j) = *(s + len - 1 - j++);
+ while (*(s + j) != '\0') {
+   *(dst + j) = *(s + len - 1 - j);
+   ++j;
+ }

Learn more about this by perusing these resources: