1

Let's say we have an array:

struct some array[] = {A, B, C, D};

and lets say we have a function which, given an index by parameter, does something with that value:

void sfrugula(size_t index){
    do_it( &array[index] );
}

now, we know we want to almost always call that function with STATIC values and not by variable, like:

sfugula(10);

is there a way to check that there is no overflow at compile time and if there is throw an error?

The point is to hard limit and check the parameter at compile time (if possible), as this may be applied not only on array but maybe even just to some variable.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Lesto
  • 2,260
  • 2
  • 19
  • 26
  • Better to have "DEBUG" version with all checks available than this. – Matt Mar 24 '15 at 11:43
  • In C, there is no inherit checking of array bounds. So the called function needs to know the number of entries in the array and check the parameter against that limit. That would be at execution time. I know of no way to check at compile time. – user3629249 Mar 24 '15 at 11:52
  • What does this mean? A debug version without compile time check means I have to check all possible outcome with a test program. A compilation check is safer, and faster. Then a test still should be run to check for other error – Lesto Mar 24 '15 at 11:53
  • @user3629249 I know there is no check, what I'm asking for is there is some directive to hard limit values at compile time. I understand variable can't be check at runtime with this method, and the use with array is just an example. But static access will be a little safer. – Lesto Mar 24 '15 at 11:56

5 Answers5

1

here my solution, it use enum and the X macro:

i created an external file "ports.h". The left element of X() is the "nice name used by user", and the right is the corresponding REAL value (or unique part of it as show below)

#ifdef DDRA && PORTA && PINA
X(A, AAA)
#endif
#ifdef DDRB && PORTB && PINB
X(B, BBB)
#endif

then into another file i declared the enum (A, B, ....) and the parallel array of pointer to real elements (witch in this case are my_AAA, my_BBB, etc...)

#define SEP ,
#define X(a, b) a SEP
enum PORTS {
    #include "ports.h"
};
#undef X

/* here we initialize the array of structure */
#define X(a, b) &my_##b SEP
static const uint8_t *array[] =
{
    #include "ports.h"
};
#undef X
#undef SEP

and in the end just change our function to use the enum

void sfrugula(enum PORTS p){
    do_it( &array[p] );
}

the only different thing i MUST do is to use the enum instead of the numeric value when using the function, BUT the compiler will NOT throw a warning if i forgot; now I'm looking for some typedef magic to make that happen (in C++ it is already fine if you use"-Wenum-compare" witch is by default if using "-Wall")

Community
  • 1
  • 1
Lesto
  • 2,260
  • 2
  • 19
  • 26
0

Use an enumeration (enum). This way you can limit the values of a variable to a certain set of integers. Note that enums work only as integers and are good for a relatively small set of values.

dimm
  • 1,792
  • 11
  • 15
  • Yes, I'm working on a mix of x macro and ifdef. Will post if I will have something working – Lesto Mar 24 '15 at 12:21
0

Even when the definition and usage are side by side, the compiler won't check the array indexing.

int array[3];
array[10] = 0;

Here is a solution to contrive it, but clumsy:

#include<stdio.h>

#define ARRMAX  3
#define INDEX   10

int main()
{
    int array[ARRMAX];
    #if INDEX >= ARRMAX
    #error Array index is out of range
    #endif
    array[INDEX] = 0;
    return 0;
}

Compiler output:

test.c(10) : fatal error C1189: #error :  Array index is out of range

But you can't do it within the function, you would have to do it when your function is called, knowing what the function does. Far better to tackle this at run time, in your function, then you can check both static and variable values passed.

Weather Vane
  • 33,872
  • 7
  • 36
  • 56
  • Rather than rely on a pre-processor value to represent the size of the array, you could get the precompiler to help even more: `#if(INDEX >= ((sizeof array)/(sizeof array[0])))`. – Evil Dog Pie Mar 24 '15 at 12:29
  • I through about this, if I use a define instead the function (witch will do the check and call the function), BUT no #if inside #define. Nice idea but unfeasible – Lesto Mar 24 '15 at 12:30
0

Inside the sfrugula function, no, there is no way to do a compile time check.

C uses a build system that is quite simplistic, and the compiler does not concern itself with these sorts of things. It really just goes through your code spitting out assembler for each function based on the argument list and the statements inside them. Sure it could do these types of checks, but remember that an out of bounds array access is still compliant C code, and beyond enforcing compliance most C compilers make no judgements about how you might like to use or abuse the language.

The pre-processor on the other hand provides some ability for compile time validation, but this does not extend to what you want to do. So your best option is to check the range at each place sfugula is called, or add a run time check that you only use in debug mode. However, unless your system is severely resource constrained, it is generally good practice to just include the error check in production code with an appropriate failure mechanism. Working through how the program could deal with such an error, even if you think it could be mitigated through static checking, will make your program more robust.

Jon
  • 496
  • 2
  • 8
  • I would like to find a static solution. This is because the system are really limited in resources (64byte! Of ram, for example) – Lesto Mar 24 '15 at 13:20
  • Have you checked if your toolchain has a static analyser? Otherwise you could roll your own. Might be best to add the microcontroller tag to your question or you'll just get a lot of answers about adding a runtime check. – Jon Mar 24 '15 at 13:26
  • Also in embedded it is pretty normal to just see an assert before each function call in this sort of situation. – Jon Mar 24 '15 at 13:30
  • GCC does not do static analysis. Yet :) for assert we are going into runtime, and outside the question boundaries – Lesto Mar 24 '15 at 13:38
  • 1
    You can do compile time asserts in C. Essentially you just have a macro that evaluates to a syntax error. See [this](http://stackoverflow.com/questions/807244/c-compiler-asserts-how-to-implement) – Jon Mar 24 '15 at 13:54
0

This doesn't directly answer the question, as it doesn't provide a mechanism for doing the check at compile time. However, in the absence of an (obvious) way to do that, I would recommend that, unless you're building a library API that will be called by third party developers, you should provide a mechanism that does run-time range checking and can be disabled for release builds when you've completed your exhaustive testing.

(For public APIs it is pretty much essential to leave the range checking in.)

You could wrap the call to the function in a macro, which can be disabled for release builds.

#ifdef DEBUG
    #define SAFE_sfrugula(index) do\
    {\
        if(index < ((sizeof array) / (sizeof array[0]))) \
            sfrugula(index);\
        else\
        {
            printf("sfrugula index out of range on line %d",__LINE__);\
            exit(-1);\
        }\
    } while(0)
#else
    #define SAFE_sfrugula(index) sfrugula(index)
#endif
Evil Dog Pie
  • 2,300
  • 2
  • 23
  • 46