如何在 C 中编写链接其他函数的函数

how to write a function that links other functions in C

假设我有函数 A、B 和 C。

我想编写一个如下所示的函数:

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

其中数组对应于将调用第一个列表中的哪个元素。换句话说,当A完成时,它启动第二个元素B,当B完成时它调用第三个元素C,当C完成时什么都不调用。

然后链接器将展开到

generic preprocessing
run A
generic postprocessing

generic preprocessing
run B
generic postprocessing

generic preprocessing 
run C
generic postprocessing

我的想法是,这样可以更轻松地 link 一起使用函数,并且可以节省我编写预处理和后处理步骤的时间。还有组织、防错、可理解性等……这个想法在 C 中可能吗?我需要使用 C++ 吗?我该如何开始实施这样的想法?

我正在使用 stm32ide 作为我的编译器,因为此代码将 运行 在嵌入式设备上。

您可以通过设置一些“处理”来做到这一点 class 来存储指向您的函数的指针以及您希望在它们之间建立的链接:

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); }
        }
    }
};

然后要使用它,你只需要添加你的功能和链接,然后调用 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;
}

在此处查看实际效果:https://ideone.com/M1Qj6f

如果我理解正确的话,你想将一个函数作为参数传递给另一个函数。

对于c++你可以使用函数指针。

#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();
}

如果你想要更明确的类型,你可以写

#include <iostream>

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


int main()
{
    helloWorld();

    void(*secondHelloWorld)() = helloWorld;

    void(*thridHelloWorld)() = helloWorld;

    secondHelloWorld();
    thirdHelloWorld();

    std::cin.get();
}

我无法帮助您准确地实现它。我需要知道你的要求。

HTH

你的问题应该得到澄清。如果我理解得很好,你想包装一个函数,就像在上下文管理器中所做的那样。您应该准确说明函数的签名是什么 ABC 以及必须如何使用 {{0,1,0},{0,0,1},{0,0,0}}.

为了简单起见,我假设这三个函数不带参数,也不 return 任何东西。

#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;       
}

结果:

generic preprocessing
run A
generic postprocessing

generic preprocessing
run B
generic postprocessing

generic preprocessing
run C
generic postprocessing

您显然可以调整 flinker 的签名来传递一些参数。

难的是:Linker(A,B,C,{{0,1,0},{0,0,1},{0,0,0}});不能用C写,语言不足:

  • 函数的自动处理或可变数量的参数:您必须给出数字提示,函数将不得不猜测类型
  • 语言中不​​存在乱码多维数组。

换句话说,我可以想象如何在 Python 中编写能够接受该语法(除了分号)但在 C 中不能接受的东西。构建一个 thing 能够处理一堆函数并根据 something 链接它们不是问题,可以在 C 中完成。但我猜不出 something 应该是,以及您打算如何在尊重 C 语法的同时将函数和 something 传递给 thing

假设我明白你要做什么,并假设所有函数都具有相同的 return 类型和参数列表,你可以设置一个函数指针数组和一个整数数组来指示哪个从该列表中执行的函数:

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} );
}

输出:

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

如果函数具有不同的 return 类型,或者如果它们具有相同的 return 类型但采用不同的参数列表(甚至相同的参数列表具有不同的值),那么这将需要充实一点。您可能需要创建一个 C 等效的“仿函数”(基本上是一个抽象出函数 return 类型和其他细节的结构类型)。但它应该会给你一些想法。