6

I've been thinking about a way to make it easier to safely use math operations with C's basic datatypes (e.g. using the CERT C coding standard). So far, I've come up with something like this:

#include <stdlib.h>
#include <stdio.h>
#include <limits.h>

#define safe_add(x, y) _Generic((x + y),                    \
                            unsigned int: safe_add_uint,    \
                           unsigned long: safe_add_ulong    \
                       )(x, y, __FILE__, __LINE__)

unsigned long
safe_add_ulong(unsigned long x, unsigned long y,
               const char* filename, int line_num)
{
    if (x < ULONG_MAX - y)
        return x + y;
    else {
        fprintf(stderr,
                "Integer wrap-around occurred, File: %s, Line: %d\n",
                filename, line_num);
        exit(EXIT_FAILURE);
    }
}

unsigned int
safe_add_uint(unsigned int x, unsigned int y,
              const char* filename, int line_num)
{
    if (x < UINT_MAX - y)
        return x + y;
    else {
        fprintf(stderr,
                "Integer wrap-around occurred, File: %s, Line: %d\n",
                filename, line_num);
        exit(EXIT_FAILURE);
    }
}

int
main()
{        
    /*  
     *  usual arithmetic conversions results in this calling
     *  the uint version of safe_add...
     */
    safe_add(2000000000, 3000000000u));

    printf("We shouldn't get here...(unless unsigned int uses more than 32 bits)\n");
}

Output of the above would be something similar to:

Integer wrap-around occurred, File: /.../main.c, Line: 41

and the program exits with a failure code (assuming the OS supports that).

Obviously, additional operations and types need to be added as well as handling signed arithmetic, but are there any problems with this overall method that I may be missing?

Is there perhaps an easier way to write this that I've overlooked?

acarlow
  • 914
  • 1
  • 7
  • 13

1 Answers1

0

This code could be library-esque, except that it fprintfs to stderr. Instead, you could figure out a way to communicate the error directly to the caller, who could then choose to gracefully deal with it. You could split these such that the error-reporting and exiting code is separate from the "quiet" code which performs the computation(s) and notices an error.

For example, you'll notice that several C functions[1] return an int value, even though they're dealing with bytes. This allows them the "room" to communicate the special EOF condition, along with all byte-values.

If you cannot communicate your error-condition in the return-value, you could use a pointer parameter to communicate status back to the caller.

[1] Such as fgetc

Shao
  • 537
  • 3
  • 7
  • Actually, I omitted **errno** on purpose. One needs to consider thread-safety with subjects like **errno**, **strtok**, etc. I'd prefer avoiding them unless needing them, personally. – Shao Aug 15 '14 at 01:57
  • Bryan Chen: Relative to what? POSIX threads?: Yes. Win32 threads?: It depends[1]. C11 threads?: Yes. Pre-C11?: It depends. [1] http://www.microsoft.com/msj/0799/Win32/Win320799.aspx – Shao Aug 15 '14 at 02:12