Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Solution

Note

Clicking the button below automatically creates a blood oath with the course. It only works if you actually tried to do the exercise beforehand. Click at your own risk.

Reveal the solution.

Your CPU contains special instructions to detect overflows and underflows. Standard C doesn’t. Yet, you can use compiler-specific builtins that will compile to optimized instructions! Both GCC and Clang define the following:

// Respectively add/subtract/multiply `a` and `b` and store the result in
// `result`, returning `true` if there was an overflow/undeflow. The `T` type
// represents whatever integer type you want.
bool __builtin_add_overflow(T a, T b, T* result);
bool __builtin_sub_overflow(T a, T b, T* result);
bool __builtin_mul_overflow(T a, T b, T* result);

Unfortunately, these builtins are not standardized. For instance, MSVC (Microsoft’s compiler) doesn’t include the exact same builtins.

In fact, C does have standardized functions now! C23 (the 2023 revision of the C programming language) added a new standard header for overflowing arithmetic. See https://en.cppreference.com/w/c/header/stdckdint.html.

However, as it’s usually the case with new standards, MSVC doesn’t support it yet (if ever?). That’s why we stick with the good old builtins anyway.

OK, let’s consider this simple function:

#include <stdbool.h>
#include <stdio.h>

void print_addition(int a, int b) {
    int sum;
    bool overflow = __builtin_add_overflow(a, b, &sum);
    if (overflow) {
        printf("There's been an overflow!\n");
    } else {
        printf("%d + %d == %d\n", a, b, sum);
    }
}

GCC compiles it to the assembly code below. Notice the jo instruction (“jo” stands for “Jump if Overflow”). As the name indicates, it jumps if the last addl instruction overflowed.

.LC0:
        .string "There's been an overflow!"
.LC1:
        .string "%d + %d == %d\n"
print_addition:
        movl    %edi, %ecx      ; `a` is in the EDI register.
        movl    %esi, %edx      ; `b` is in the ESI register (I don't know why GCC generates this).
        addl    %esi, %ecx      ; Add `b` to `a`.
        jo      .L3             ; Jump to L3 if it overflowed.
        movl    %edi, %esi      ; Print "{a} + {b} == {c}" using printf.
        xorl    %eax, %eax
        movl    $.LC1, %edi
        jmp     printf
.L3:
        movl    $.LC0, %edi     ; Print "There's been an overflow!" using puts.
        jmp     puts

Documentation: