1

Lets say I have functions A, B, & C.

I would like to write a function which looks like:

Linker(A,B,C,{{0,1,0},{0,0,1},{0,0,0}});

where the arrays correspond to which element in the first list will be called. In other words, when A finishes, it starts the second element B, when B finishes it calls the third element C, when C finishes nothing is called.

Linker would then unroll into

generic preprocessing
run A
generic postprocessing

generic preprocessing
run B
generic postprocessing

generic preprocessing 
run C
generic postprocessing

The idea being that this would make it easier to link functions together, and would save me some time in writing the pre and postprocessing steps. Also organization, error-proofing, understandability, etc... Is this Idea possible in C? would I need to use C++? how do I begin implementing an idea like this?

I am using stm32ide as my compiler as this code will run on an embedded device.

Ivan Viti
  • 21
  • 3
  • 2
    C and C++ are *very* different languages. Which are you using? – scohe001 Dec 21 '20 at 16:06
  • 1
    I will make code less readable I think that it is a X-Y problem. Tall more what you want to achieve. – 0___________ Dec 21 '20 at 16:06
  • 1
    It's possible in C, you'll need to use function pointers. Read more: https://stackoverflow.com/questions/840501/how-do-function-pointers-in-c-work – Tumbleweed53 Dec 21 '20 at 16:06
  • In C such things are most lioften done using function pointers and in C++ using lambdas or std::bind. – Öö Tiib Dec 21 '20 at 16:08
  • If this ```{{0,1,0},{0,0,1},{0,0,0}}````the input to the functions? For example, ```{0, 1, 0}``` is the input to the first function? – MacOS Dec 21 '20 at 16:28

5 Answers5

2

You could do this by setting up some "processing" class that stores pointers to your functions and the links you want to establish between them:

class processor {
private:
    std::vector<void (*)()> funcs;
    std::vector<std::pair<int, int>> links;
public:
    void add_func(void (*func)()) { funcs.push_back(func); }
    void link(int from, int to) { links.push_back({from, to}); }
    void call(int indx) {
        // Make the call
        funcs.at(indx)();
 
        // Call any links
        for(auto it : links) {
            if(it.first == indx) { call(it.second); }
        }
    }
};

Then to use it, you just need to add your functions and links, and then call call():

int main() {
    processor p;
    p.add_func(A);
    p.add_func(B);
    p.add_func(C);
 
    p.link(0, 1); // A -> B
    p.link(1, 2); // B -> C
 
    p.call(0); // Call A
 
    return 0;
}

See it in action here: https://ideone.com/M1Qj6f

scohe001
  • 15,110
  • 2
  • 31
  • 51
0

If I understand you correctly you want to pass a function as a parameter to another function.

For c++ you can use function pointers.

#include <iostream>

void helloWorld()
{
    std::cout << "Hello World" << std::endl;
}


int main()
{
    helloWorld();

    # Here we get the memory adress of the function helloWorld.
    auto secondHelloWorld = &helloWorld;

    # Here, an implicit converstion is going on.
    auto thridHelloWorld = helloWorld;

    secondHelloWorld();
    thirdHelloWorld();

    std::cin.get();
}

If you want to be more explicit with the types, you can write

#include <iostream>

void helloWorld()
{
    std::cout << "Hello World" << std::endl;
}


int main()
{
    helloWorld();

    void(*secondHelloWorld)() = helloWorld;

    void(*thridHelloWorld)() = helloWorld;

    secondHelloWorld();
    thirdHelloWorld();

    std::cin.get();
}

I can not help you with how you should precisly implement this. I would need to know you requirements.

HTH

MacOS
  • 1,149
  • 1
  • 7
  • 14
0

Your question should be clarified. If I understand well, you want to wrap a function, as done in a context manager. You should precise what is the signature of your functions A, B, C and how must be used {{0,1,0},{0,0,1},{0,0,0}}.

So to keep it simple, I'll assume that these three functions takes no parameter and do not return anything.

#include <stdio.h>

void context_manager(
    void (*f)(),
    void (*enter)(),    
    void (*exit)()                                                       
) {   
    enter();        
    f();
    exit();
}

void my_enter() { printf("generic preprocessing\n"); }
void my_exit() { printf("generic postprocessing\n\n"); }
void a() { printf("run A\n"); }
void b() { printf("run B\n"); }
void c() { printf("run C\n"); }

void linker(void **fs, unsigned n) {
    for (unsigned i = 0; i < n; i++) {
        context_manager(fs[i], my_enter, my_exit);
    }   
}

int main() { 
    void * fs[] = {a, b, c};
    linker(fs, sizeof(fs) / sizeof(void *));
    return 0;       
}

Result:

generic preprocessing
run A
generic postprocessing

generic preprocessing
run B
generic postprocessing

generic preprocessing
run C
generic postprocessing

You can obviously adapt the signature of f and linker to pass some parameter(s).

mando
  • 135
  • 1
  • 8
0

The hard part is that: Linker(A,B,C,{{0,1,0},{0,0,1},{0,0,0}}); cannot be written in C. The language lacks:

  • automatic processing or variable numbers of parameters for a function: you have to give a hint for the number and the function will have to guess the type
  • litteral multi-dimensional arrays do not exist in the language.

Said differently, I can imagine how to write something able to accept that syntax (apart from the semicolon) in Python, but not in C. Building a thing able to process a bunch of functions and chain them according to something is not a problem and can be done in C. But I cannot guess what the something should be, and how you intend to pass the functions and the something to the thing while respecting C syntax.

Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252
0

Assuming I understand what you're going for, and assuming all the functions have the same return type and argument lists, you could set up an array of function pointers and an array of integers to indicate which function to execute out of that list:

void A(void) { puts( "In A" ); }
void B(void) { puts( "In B" ); }
void C(void) { puts( "In C" ); }

/**
 * Call each of the functions in f based on the values in seq;
 * each seq[i] is treated as an index into f.
 *
 * A negative value in seq[i] indicates the end of the sequence.
 *
 * Inputs:
 *    f     - list of functions we want to execute
 *    seq   - specifies the order in which the functions are to be executed
 */
void Linker( void (*f[])(void), int *seq )
{
  for ( int i = 0; seq[i] >= 0; i++ )
  {
    f[seq[i]]();
  }
}

int main( void )
{
  /**
   * Use compound literals to set up each array.
   */
  Linker( (void (*[])(void)) {A, B, C}, (int []) {0, 1, 2, 2, 1, 2, 0, 0, 0, -1} );
}

Output:

In A
In B
In C
In C
In B
In C
In A
In A
In A

If the functions have different return types, or if they have the same return types but take different parameter lists (or even the same parameter lists with different values), then this will need to be fleshed out a bit. You may need to create a C equivalent of a "functor" (basically a struct type that abstracts away the function return type and other details). But it should give you some ideas.

John Bode
  • 119,563
  • 19
  • 122
  • 198