Допустим, у меня есть функции 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
Идея заключалась в том, что это упростит связывание функций и сэкономит мне время при написании шагов предварительной и последующей обработки. Также организация, защита от ошибок, понятность и т. д. Возможна ли эта идея в C? нужно ли мне использовать С++? как мне начать реализовывать такую идею?
Я использую stm32ide в качестве компилятора, так как этот код будет работать на встроенном устройстве.
Я сделаю код менее читаемым, я думаю, что это проблема X-Y. Чем больше вы хотите достичь.
Это возможно в C, вам нужно будет использовать указатели на функции. Подробнее: stackoverflow.com/questions/840501/…
В C такие вещи чаще всего выполняются с помощью указателей на функции, а в C++ — с помощью лямбда-выражений или std::bind.
Если это {{0,1,0},{0,0,1},{0,0,0}}````the input to the functions? For example,
{0, 1, 0}``` является входом для первой функции?
Вы можете сделать это, настроив некоторый класс «обработки», в котором хранятся указатели на ваши функции и связи, которые вы хотите установить между ними:
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();
}
Я не могу помочь вам с тем, как именно это реализовать. Мне нужно знать ваши требования.
ХТН
Ваш вопрос должен быть уточнен. Если я правильно понимаю, вы хотите обернуть функцию, как это делается в контекстном менеджере. Вы должны уточнить, что является сигнатурой ваших функций A
, B
, C
и как они должны использоваться {{0,1,0},{0,0,1},{0,0,0}}
.
Поэтому для простоты я предполагаю, что эти три функции не принимают параметров и ничего не возвращают.
#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
Очевидно, вы можете адаптировать подпись f
и linker
для передачи некоторых параметров.
Сложность в том, что: Linker(A,B,C,{{0,1,0},{0,0,1},{0,0,0}});
нельзя написать на C. В языке отсутствуют:
Другими словами, я могу представить, как написать что-то, способное принимать этот синтаксис (кроме точки с запятой) на Python, но не на C. Создать вещь, способную обрабатывать кучу функций и связывать их в соответствии с чем-то, не проблема и можно сделать в C. Но я не могу угадать, что должно быть, и как вы собираетесь передавать функции и что-то в вещь, соблюдая синтаксис C.
Предполагая, что я понимаю, к чему вы стремитесь, и предполагая, что все функции имеют одинаковый тип возвращаемого значения и списки аргументов, вы можете настроить массив указателей на функции и массив целых чисел, чтобы указать, какую функцию выполнять из этого списка:
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
Если функции имеют разные типы возвращаемых значений или если они имеют одинаковые типы возвращаемых значений, но принимают разные списки параметров (или даже одни и те же списки параметров с разными значениями), то это необходимо немного конкретизировать. Возможно, вам потребуется создать C-эквивалент "функтора" (в основном это тип структуры, который абстрагирует тип возвращаемого значения функции и другие детали). Но это должно дать вам некоторые идеи.
C и C++ очень разные языки. Что вы используете?