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: