4

I have an embedded OS that needs its resources to be defined statically by compile time.

So e.g.

#define NUM_TASKS 200

At the moment, I have one header file where every developer needs to declare the tasks he/she needs, kind of like this:

#define ALL_TASKS  ( \
                     1 + \  /* need one task in module A */
                     2   \  /* need two tasks in module B */
                   )

and during compilation of the OS, there is a check:

#if (ALL_TASKS > NUM_TASKS)
#error Please increase NUM_TASKS in CONF.H
#endif

So when I compile and more Tasks are needed the compilation stops and gives explicit notice that the static OS won't have enough tasks for this to work.

So far so good.


Enter the lazy programmer that forgets to add the tasks he added in module A to the global declaration file in directory x/y/z/foo/bar/baz/.

What I would like is the following construct, which I can't seem to achieve with any macro tricks I tried:

Have macros to declare the resources needed in a module like so:

OS_RESERVE_NUMBER_OF_TASKS(2)

in the modules adds 2 to the global number of Tasks.

my first rough idea was something like this:

#define OS_RESERVE_NUMBER_OF_TASKS(max_tasks)       #undef RESOURCE_CALC_TEMP_MAX_NUM_TASKS \
                                                    #define RESOURCE_CALC_TEMP_MAX_NUM_TASKS    RESOURCE_CALC_MAX_NUM_TASKS + max_tasks \
                                                    #undef RESOURCE_CALC_MAX_NUM_TASKS  \
                                                    #define RESOURCE_CALC_MAX_NUM_TASKS     RESOURCE_CALC_TEMP_MAX_NUM_TASKS    \
                                                    #undef RESOURCE_CALC_TEMP_MAX_NUM_TASKS

but that doesn't work because a #define in a #define does not work.


So the question basically is:

Do you have an idea how it would be possible to split the calculation of the number of tasks into multiple files (namely the modules themselves) and have that number comapred to the defined max number of tasks during compile time?

If this isn't solvable with pure C preprocessor, I'll have to wait until we change the make system to scons...

AstroCB
  • 12,337
  • 20
  • 57
  • 73
TabascoEye
  • 656
  • 5
  • 24
  • I don't believe this is possible in pure C as it would require preprocessing information to be communicated across translation units (C files/modules). – Drew McGowen Aug 15 '14 at 13:41
  • 2
    If C11 is an option, and you just want compilation to fail, you might be able to use `static_assert` instead of having to use weird preprocessor hacks. – Drew McGowen Aug 15 '14 at 13:54

2 Answers2

3

Can you require that tasks have some ID or similar which all task users must use?

tasks.h

enum {
    TASK_ID_TASK_A_1,
    TASK_ID_TASK_B_1,
    TASK_ID_TASK_B_2,
    NUM_TASKS
};
void * giveResource(int taskId, int resourceId);

user_module_B.c

#include "tasks.h"
...
resource = giveResource(TASK_ID_TASK_B_1, resource_id_B_needs);
user694733
  • 15,208
  • 2
  • 42
  • 68
  • nice idea. That would make developers conscious of the resources because they cannot simply create antoher one before declaring its ID in the enum. – TabascoEye Aug 15 '14 at 14:10
  • @TabascoEye If you wish to link some other data to ID numbers, you might find the [techniques in here](http://stackoverflow.com/q/10446827/694733) useful. – user694733 Aug 15 '14 at 14:29
1

You can update the value of a macro in the course of translating one unit using the Boost Preprocessor library's evaluated slots functionality. It defines several "slots" that can be treated as mutable global variables by preprocessor code, which will let you add to a value as you go along rather than defining it with a single expression.

(It's pure standard C, but the code that implements it is rather complicated)

You can't do it in one line, because it relies on calls to #include, and that means you can't wrap it up into a pretty one-liner macro, but it would look something like this:

#define TASK_SLOT 2    //just pick one
#define ALL_TASKS BOOST_PP_SLOT(TASK_SLOT)

#define BOOST_PP_VALUE 1 + 2
#include BOOST_PP_ASSIGN_SLOT(TASK_SLOT)    // ALL_TASKS now evals to 3

#define BOOST_PP_VALUE 3 + ALL_TASKS
#include BOOST_PP_ASSIGN_SLOT(TASK_SLOT)    // ALL_TASKS now evals to 6

As Drew comments (I may have misunderstood your req.), this is only valid for one translation unit. Which is fine if you have a central NUM_TASKS and each unit is allowed to add up its own ALL_TASKS figure.

If you need the value to increment across multiple .c files (so that the final ALL_TASKS is the total across all modules, not for one), you'd need to wrap them up into a unity build for this technique to work, which most people reckon is a bad idea. A more advanced build system would then probably be appropriate, because the preprocessor is only designed to work on single units.

Alex Celeste
  • 12,824
  • 10
  • 46
  • 89