Template for handling function pointer functions of heterogeneous signature in C

So, I have a huge set of functions for reading inputs from some form source:

ErrCode_t in_func1(t1_t * const data1);
ErrCode_t in_func2(t2_t * const data2);
...

Some trigger functions telling me if I can call the functions above:

TrCode_t tr_func1();
TrCode_t tr_func2();
...

and related functions for recording data:

void out_func1(t1_t const * const data1, const uint32_t handled_error);
void out_func2(t2_t const * const data2, const uint32_t handled_error);
...

There is also a rather complicated algorithm depending on the trigger functions, which decides whether I can call the input function or not. (This is a simplified picture, more than one trigger function and timers provided for each I / O).

This algo, but basically says: If the trigger says yes, call the input function with a pointer to a data variable, check for an error, do some checking, and then pass the pointer to the updated variable for output.

 void execute_f1(t1_t * const pData1)
 {
    if(evalTr(tr_func1()))
    {
      const ErrCode_t myErr = in_func1(pData1);
      const uint32_t myOutErr = evalError(myErr);

      out_func1(pData1,myOutErr);
    }
 }

( evalTr evalError , )

,

 void execute_io(???)

. , , . , , , :

ErrCode_t my_in_func1(void * const pData1)
{
    t1_t * const data1 = (t1_t*) pData1;
    return in_func1(data1);
}

:

 void my out_func2(void const * const data2, const uint32_t handled_error) {...}

, , . . - , "" execute_io , ?

: barak manos:

system_interface.h

 ErrCode_t in_func1(t1_t * const data1);
 /* some 500 more of them */

 TrCode_t tr_func1();
 /* some 500 more of them */

 void out_func1(t1_t const * const data1, const uint32_t handled_error);
 /* some 500 more of them */

my_code.c

 static ErrCode_t my_in_func1(void * const data1)
 {
    t1_t * const data1 = (t1_t*) pData1;
    return in_func1(data1);
 }
 /* and some 500 more wrappers */

 static void my_out_func1(void const * const pData1, const uint32_t handled_error)
 {
    t1_t const * const data1 = (t1_t) pData1;
    out_func1(pData1, handled_error);
    return;
 }
 /* and some 500 more wrappers */

typedef ErrCode_t (*inFuncPtr)(void * const);
typedef void (*outFuncPtr)(void const * const, const uint32_t);
typedef TrCode_t (*trFuncPtr)();

execute_io(inFuncPtr inFunc, outFuncPtr outFunc, trFuncPtr trFunc, void * pData)
{
   if(evalTr((*trFunc)()))
   {
      const ErrCode_t myErr = (*inFunc)(pData);
      const uint32_t myOutErr = evalError(myErr);

      (*outFunc)(pData,myOutErr);
   }
   return;
}

void do_all_my_work()
{
   {
     t1_t data1;
     execute_io(&my_in_func1, &my_out_func1, &tr_func1, &data1);
   }
   {
     t2_t data2;
     execute_io(&my_in_func2, &my_out_func2, &tr_func2, &data2);
   }
   /* and some 499 other calls */
}

, -. ( , , , , )

+4
1

-, , , , . , - . , , , , . , , , , , . , , , , . , , 2 , c 64 (8 ). , . /. , , 8 , , 0 7 , 8 , , , 64- .

    /*
 * Test.c
 *
 *  Created on: May 14, 2015
 *      Author: tiger
 */
#include <stdio.h>

typedef int ErrCode_t;
typedef int TrCode_t;
typedef unsigned int uint32_t;
typedef unsigned char uint8_t;
typedef unsigned long long int uint64_t;

typedef int t1_t;
typedef short t2_t;
typedef float t3_t;
typedef double t4_t;
typedef long long int t5_t;

#define MAX_DATA_TYPE_SIZE ((uint32_t)64) //or whatever the size is of your largest data type

uint32_t evalTr(TrCode_t code);
uint32_t evalError(ErrCode_t code);

ErrCode_t in_func1(t1_t* const data1);
ErrCode_t in_func2(t2_t* const data2);
ErrCode_t in_func3(t3_t* const data3);
ErrCode_t in_func4(t4_t* const data4);
ErrCode_t in_func5(t5_t* const data5);

TrCode_t tr_func1();
TrCode_t tr_func2();
TrCode_t tr_func3();
TrCode_t tr_func4();
TrCode_t tr_func5();

void out_func1(t1_t const* const data1, const uint32_t handled_error);
void out_func2(t2_t const* const data2, const uint32_t handled_error);
void out_func3(t3_t const* const data3, const uint32_t handled_error);
void out_func4(t4_t const* const data4, const uint32_t handled_error);
void out_func5(t5_t const* const data5, const uint32_t handled_error);

typedef struct
{
    TrCode_t (*tr_func)(void);
    ErrCode_t (*in_func)(void* const data);
    void (*out_func)(const void* const data, const uint32_t handled_error);
}IOSet;

#define FUNCTION_COUNT ((uint32_t)5)
IOSet ioMap[FUNCTION_COUNT] =
{
    {.tr_func = (void*)&tr_func1, .in_func = (void*)&in_func1, .out_func = (void*)&out_func1},
    {.tr_func = (void*)&tr_func2, .in_func = (void*)&in_func2, .out_func = (void*)&out_func2},
    {.tr_func = (void*)&tr_func3, .in_func = (void*)&in_func3, .out_func = (void*)&out_func3},
    {.tr_func = (void*)&tr_func4, .in_func = (void*)&in_func4, .out_func = (void*)&out_func4},
    {.tr_func = (void*)&tr_func5, .in_func = (void*)&in_func5, .out_func = (void*)&out_func5}
};

void execute_io(IOSet io, void * const pData)
{
    if(evalTr(io.tr_func()))
    {
        const ErrCode_t myErr = io.in_func(pData);
        const uint32_t myOutErr = evalError(myErr);

        io.out_func(pData,myOutErr);
    }
}

void do_all_my_work()
{
    uint32_t i;
    //allocate a buffer sufficiently large to hold any of the data types on the stack
    // + 8 to allow correcting pointer for any alignment issues
    uint8_t dataBuffer[MAX_DATA_TYPE_SIZE + 8];
    uint64_t dataHandle = (uint64_t)&dataBuffer;
    //ensure the dataHandle is divisible by 8 to satisfy all possible alignments
    //all 8 byte alignments are also valid 4 byte alignments
    //all 4 byte alignments are also valid 2 byte alignments
    //all 2 byte alignments are also valid 1 byte alignments

    //you can use a smaller type than uint64_t for this computation if your pointers are smaller,
    //but this should work for pointers of all sizes up to 64 bits
    if((dataHandle % 8) > 0)
    {
        dataHandle += 8ULL-(dataHandle % 8);
    }

    for(i = 0; i < FUNCTION_COUNT; i++)
    {
        execute_io(ioMap[i], (void*)dataHandle);
    }
}

uint32_t evalTr(TrCode_t code)
{
    static uint32_t result = 0;
    result ^= 1;
    return result;
}

uint32_t evalError(ErrCode_t code)
{
    return 0;
}

ErrCode_t in_func1(t1_t* const data1)
{
    *data1 = 1;
    return 0;
}

ErrCode_t in_func2(t2_t* const data2)
{
    *data2 = 2;
    return 0;
}

ErrCode_t in_func3(t3_t* const data3)
{
    *data3 = 3;
    return 0;
}

ErrCode_t in_func4(t4_t* const data4)
{
    *data4 = 4;
    return 0;
}

ErrCode_t in_func5(t5_t* const data5)
{
    *data5 = 5;
    return 0;
}


TrCode_t tr_func1()
{
    return 0;
}

TrCode_t tr_func2()
{
    return 0;
}

TrCode_t tr_func3()
{
    return 0;
}

TrCode_t tr_func4()
{
    return 0;
}

TrCode_t tr_func5()
{
    return 0;
}


void out_func1(t1_t const* const data1, const uint32_t handled_error)
{
    printf("%d\n", *data1);
    return;
}

void out_func2(t2_t const* const data2, const uint32_t handled_error)
{
    printf("%d\n", *data2);
    return;
}

void out_func3(t3_t const* const data3, const uint32_t handled_error)
{
    printf("%f\n", *data3);
    return;
}

void out_func4(t4_t const* const data4, const uint32_t handled_error)
{
    printf("%f\n", *data4);
    return;
}

void out_func5(t5_t const* const data5, const uint32_t handled_error)
{
    printf("%llu\n", *data5);
    return;
}

int main()
{
    for(;;)
    {
        do_all_my_work();
    }
    return 0;
}
0
source

All Articles