Перейти к содержанию
    

Структура указателей.

У меня каждая команда принимаемая из терминала привязана к своей функции. Функции бывают разные - возвращающие значение, не возвращающие значение, с одним аргументом, двумя аргументами и так далее.

Я решил собрать все мои функции в структуру и потом присваивать соответствующий указатель.

typedef struct 
{
    void (*fp1)(void);
    void (*fp2)(uint32_t);
    void (*fp3)(uint32_t, uint32_t);
    void (*fp4)(uint32_t, uint32_t, uint32_t);
    uint32_t (*fp5)(uint32_t);
    uint32_t (*fp6)(uint32_t, uint32_t);
    uint32_t (*fp7)(uint32_t, uint32_t, uint32_t);
    //uint32_t (*fp5)(double x, double p[], double c);
} fp;

struct command
{
    char *name;  //command name
    uint32_t minargs;
    uint32_t maxargs;
    uint32_t minval;
    uint32_t maxval;
    //uint32_t return_type;
    //void *varp;  //return pointer to variable
    fp read_func_pointer;
    fp write_func_pointer;
};

struct command commands[] = {
    {"gsm", 1, 2,  0,  0,  ???? , ???? },
    {"ifb",   0,  1,  0,  0,  ????, ???? },
    
};

Не могу никак сообразить как мне подставить указатель в команду (там где вопросительные знаки).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

У меня каждая команда принимаемая из терминала привязана к своей функции...

 

Как уже отвечал в предыдущей теме, в вашей задаче проще парсить входящий буфер в массив указателей на подстроки. Тогда arg[0] будет командой, а все остальные arg - ее параметры

Т.е. в результате должно получиться как-то так:

struct cmd {
  char* name;
  void* (*proc)(void*);
};

void* cmd1_proc(char** arg)
{
  while(NULL != *arg++){
    ..
  }
}

scruct cmd cmds[]={
  { .cmd="cmd1", .proc=cmd1_proc }, ..
}

  ..
    if(strcmp(arg[0], cmds[i].name))
       cmds[i].proc(&arg[1]);

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

в вашей задаче проще парсить входящий буфер в массив указателей на подстроки. Тогда arg[0] будет командой, а все остальные arg - ее параметры

+1. Я тоже так делаю.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Как уже отвечал в предыдущей теме, в вашей задаче проще парсить входящий буфер в массив указателей на подстроки. Тогда arg[0] будет командой, а все остальные arg - ее параметры

Т.е. в результате должно получиться как-то так:

struct cmd {
  char* name;
  void* (*proc)(void*);
};

void* cmd1_proc(char** arg)
{
  while(NULL != *arg++){
    ..
  }
}

scruct cmd cmds[]={
  { .cmd="cmd1", .proc=cmd1_proc }, ..
}

  ..
    if(strcmp(arg[0], cmds[i].name))
       cmds[i].proc(&arg[1]);

то есть

 void* (*proc)(void*);

это генерик указатель? Я могу подставить любую функцию?

 

при подстановке получаю:

Error[Pe144]: a value of type "uint32_t (*)(uint32_t, uint32_t)" cannot be used to initialize an entity of type "void *(*)(void *)"

Изменено пользователем Jenya7

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Можно сделать так

 

#include <stdint.h>
#include <stdarg.h>

typedef uint32_t (*fp)(va_list ap);

// void (*fp1)(void);
uint32_t fp1(va_list ap)
{
 return 0;
}

// void (*fp2)(uint32_t);
uint32_t fp2(va_list ap)
{
 uint32_t p1;

 p1 = va_arg(ap, uint32_t);
 return 0;
}

// void (*fp3)(uint32_t, uint32_t);
uint32_t fp3(va_list ap)
{
 uint32_t p1, p2;

 p1 = va_arg(ap, uint32_t);
 p2 = va_arg(ap, uint32_t);  
 return 0;
}

// void (*fp4)(uint32_t, uint32_t, uint32_t);
uint32_t fp4(va_list ap)
{
 uint32_t p1, p2, p3;  

 p1 = va_arg(ap, uint32_t);
 p2 = va_arg(ap, uint32_t);
 p3 = va_arg(ap, uint32_t);  
 return 0;
}

// uint32_t (*fp5)(uint32_t)
uint32_t fp5(va_list ap)
{
 uint32_t result = 0;
 uint32_t p1;

 p1 = va_arg(ap, uint32_t);

 result = p1 * p1;
 return result;
}

// uint32_t (*fp6)(uint32_t, uint32_t);
uint32_t fp6(va_list ap)
{
 uint32_t result = 0;
 uint32_t p1, p2;

 p1 = va_arg(ap, uint32_t);
 p2 = va_arg(ap, uint32_t);

 result = p1 * p2;
 return result;
}

uint32_t exec(fp f, ...)
{
 va_list ap; uint32_t result;

 va_start(ap, f);
 result = f(ap);
 va_end(ap);    
 return result;
}

struct command
{
   char *name;  //command name

   fp read_func_pointer;
   fp write_func_pointer;
};

struct command commands[] = {
   {"gsm", fp1, fp2 },
   {"ifb", fp3, fp4 },
   {"bdsm", fp5, fp6 },
};

int main()
{
 int res; uint32_t p1 = 1, p2 = 2, p3 = 3;  

 // void (*fp1)(void);  
 exec(commands[0].read_func_pointer);  

 // void (*fp2)(uint32_t);
 exec(commands[0].write_func_pointer, p1);

 // void (*fp3)(uint32_t, uint32_t);
 exec(commands[1].read_func_pointer, p1, p2);  

 // void (*fp4)(uint32_t, uint32_t, uint32_t);
 exec(commands[1].write_func_pointer, p1, p2, p3);  

 // uint32_t (*fp5)(uint32_t)
 res = exec(commands[2].read_func_pointer, p1);  

 // uint32_t (*fp6)(uint32_t, uint32_t);  
 res = exec(commands[2].write_func_pointer, p1, p2);

 return res;
}

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Можно сделать так

 

#include <stdint.h>
#include <stdarg.h>

typedef uint32_t (*fp)(va_list ap);

// void (*fp1)(void);
uint32_t fp1(va_list ap)
{
 return 0;
}

// void (*fp2)(uint32_t);
uint32_t fp2(va_list ap)
{
 uint32_t p1;

 p1 = va_arg(ap, uint32_t);
 return 0;
}

// void (*fp3)(uint32_t, uint32_t);
uint32_t fp3(va_list ap)
{
 uint32_t p1, p2;

 p1 = va_arg(ap, uint32_t);
 p2 = va_arg(ap, uint32_t);  
 return 0;
}

// void (*fp4)(uint32_t, uint32_t, uint32_t);
uint32_t fp4(va_list ap)
{
 uint32_t p1, p2, p3;  

 p1 = va_arg(ap, uint32_t);
 p2 = va_arg(ap, uint32_t);
 p3 = va_arg(ap, uint32_t);  
 return 0;
}

// uint32_t (*fp5)(uint32_t)
uint32_t fp5(va_list ap)
{
 uint32_t result = 0;
 uint32_t p1;

 p1 = va_arg(ap, uint32_t);

 result = p1 * p1;
 return result;
}

// uint32_t (*fp6)(uint32_t, uint32_t);
uint32_t fp6(va_list ap)
{
 uint32_t result = 0;
 uint32_t p1, p2;

 p1 = va_arg(ap, uint32_t);
 p2 = va_arg(ap, uint32_t);

 result = p1 * p2;
 return result;
}

uint32_t exec(fp f, ...)
{
 va_list ap; uint32_t result;

 va_start(ap, f);
 result = f(ap);
 va_end(ap);    
 return result;
}

struct command
{
   char *name;  //command name

   fp read_func_pointer;
   fp write_func_pointer;
};

struct command commands[] = {
   {"gsm", fp1, fp2 },
   {"ifb", fp3, fp4 },
   {"bdsm", fp5, fp6 },
};

int main()
{
 int res; uint32_t p1 = 1, p2 = 2, p3 = 3;  

 // void (*fp1)(void);  
 exec(commands[0].read_func_pointer);  

 // void (*fp2)(uint32_t);
 exec(commands[0].write_func_pointer, p1);

 // void (*fp3)(uint32_t, uint32_t);
 exec(commands[1].read_func_pointer, p1, p2);  

 // void (*fp4)(uint32_t, uint32_t, uint32_t);
 exec(commands[1].write_func_pointer, p1, p2, p3);  

 // uint32_t (*fp5)(uint32_t)
 res = exec(commands[2].read_func_pointer, p1);  

 // uint32_t (*fp6)(uint32_t, uint32_t);  
 res = exec(commands[2].write_func_pointer, p1, p2);

 return res;
}

а как определен va_list ?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Посмотрите в stdarg.h. Он не укусит :rolleyes:

даже не знал что такой зверь существует :)

 

что то я туплю наверное - а где я передаю адресс своей функции?

 

по моему я разобрался. мне придется переписать все свои функции а я хочу подставить готовую.

Изменено пользователем Jenya7

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

даже не знал что такой зверь существует :)

 

что то я туплю наверное - а где я передаю адресс своей функции?

 

по моему я разобрался. мне придется переписать все свои функции а я хочу подставить готовую.

 

что то теперь я затупил. чего там переписывать то?

 

функцию вида

void f(int a, int b, int c)
{
...
}

привести к виду

int f(va_list ap)
{
  int a = va_arg(ap, int);
  int b = va_arg(ap, int);
  int c = va_arg(ap, int);
...
  return 0;
}

?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

что то теперь я затупил. чего там переписывать то?

 

функцию вида

void f(int a, int b, int c)
{
...
}

привести к виду

int f(va_list ap)
{
  int a = va_arg(ap, int);
  int b = va_arg(ap, int);
  int c = va_arg(ap, int);
...
  return 0;
}

?

у меня уже под 100 функций к тому же разбросанных по своим файлам. :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

ну тогда для особых любителей третьей команды можно сделать так

 

#include <stdint.h>

typedef union 
{
   void (*fp1p)(void);
   void (*fp2p)(uint32_t);
   void (*fp3p)(uint32_t, uint32_t);
   void (*fp4p)(uint32_t, uint32_t, uint32_t);
   uint32_t (*fp5p)(uint32_t);
   uint32_t (*fp6p)(uint32_t, uint32_t);
   uint32_t (*fp7p)(uint32_t, uint32_t, uint32_t);
} fp;

void fp1(void)
{
}

void fp2(uint32_t a)
{
}

void fp3(uint32_t a, uint32_t B)
{
}

void fp4(uint32_t a, uint32_t b, uint32_t c)
{
}

uint32_t fp5(uint32_t a)
{
 return a * a;
}

uint32_t fp6(uint32_t a, uint32_t B)
{
 return a * b;
}

struct command
{
   char *name;  //command name
   fp read_func_pointer;
   fp write_func_pointer;
};

struct command commands[] = 
{
   [0] = { "gsm", fp1, .write_func_pointer.fp2p = fp2 },
   [1] = { "ifb", .read_func_pointer.fp3p = fp3, .write_func_pointer.fp4p = fp4 },
   [2] = { "bdsm", .read_func_pointer.fp5p = fp5, .write_func_pointer.fp6p = fp6 },
};

int main()
{
 int res;

 commands[0].read_func_pointer.fp1p();
 commands[0].write_func_pointer.fp2p(1);
 commands[1].read_func_pointer.fp3p(1, 2);
 commands[1].write_func_pointer.fp4p(1, 2, 3);  
 res = commands[2].read_func_pointer.fp5p(1);
 res = commands[2].write_func_pointer.fp6p(1, 2);
 return res;
}

 

будет компилиться начиная с C99

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

ну тогда для особых любителей третьей команды можно сделать так

 

#include <stdint.h>

typedef union 
{
   void (*fp1p)(void);
   void (*fp2p)(uint32_t);
   void (*fp3p)(uint32_t, uint32_t);
   void (*fp4p)(uint32_t, uint32_t, uint32_t);
   uint32_t (*fp5p)(uint32_t);
   uint32_t (*fp6p)(uint32_t, uint32_t);
   uint32_t (*fp7p)(uint32_t, uint32_t, uint32_t);
} fp;

void fp1(void)
{
}

void fp2(uint32_t a)
{
}

void fp3(uint32_t a, uint32_t B)
{
}

void fp4(uint32_t a, uint32_t b, uint32_t c)
{
}

uint32_t fp5(uint32_t a)
{
 return a * a;
}

uint32_t fp6(uint32_t a, uint32_t B)
{
 return a * b;
}

struct command
{
   char *name;  //command name
   fp read_func_pointer;
   fp write_func_pointer;
};

struct command commands[] = 
{
   [0] = { "gsm", fp1, .write_func_pointer.fp2p = fp2 },
   [1] = { "ifb", .read_func_pointer.fp3p = fp3, .write_func_pointer.fp4p = fp4 },
   [2] = { "bdsm", .read_func_pointer.fp5p = fp5, .write_func_pointer.fp6p = fp6 },
};

int main()
{
 int res;

 commands[0].read_func_pointer.fp1p();
 commands[0].write_func_pointer.fp2p(1);
 commands[1].read_func_pointer.fp3p(1, 2);
 commands[1].write_func_pointer.fp4p(1, 2, 3);  
 res = commands[2].read_func_pointer.fp5p(1);
 res = commands[2].write_func_pointer.fp6p(1, 2);
 return res;
}

 

будет компилиться начиная с C99

спасибо. сейчас попробую. у меня в ИАР выставлен диалект С99.

 

большое спасибо. работает. что мне нравиться так это гибкость. всегда можно добавить в юнион недостающию функцию.

Изменено пользователем Jenya7

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

то есть

 void* (*proc)(void*);

это генерик указатель? Я могу подставить любую функцию?

Нет. Эта функция в таком виде в данном конкретном случае не нужна.

Нужно вот так, с некоторыми оговорками:

//char cmd[] = "test";//   arg1      arg2";
//char test[] = "test         arg1      arg2";
char test[] = "test2";

struct cmd {
    char* name;
    int (*cmd)(char** args);
};

int cmd_test(char** args)
{
    enum {
        ARG1=1,
        ARG2=2
    };
    int argc=ARG1;

    printf("CMD test,");

    if(!args)
    {
        printf("required parameters!\n");
        return -1;
    }

    do
    {
        switch(argc++)
        {
        case ARG1:
            printf(" ARG1: %s", *args);
            break;

        case ARG2:
            printf(" ARG2: %s", *args);
            break;

        default:
            printf("Unknown param: %s\n", *args);
            break;
        }

    }
    while(*++args);

    printf("\n");

    return 0;
}

int cmd_test2(char** args)
{
    printf("CMD test2\n");

    return 0;
}

struct cmd cmds[] =
{
    { .name = "test",   .cmd = cmd_test  },
    { .name = "test2",  .cmd = cmd_test2 },
};

int main ()
{
    int argc, i;

    argc = parse_command(test, args);

    for(i=0;i<sizeof(cmds)/sizeof(struct cmd); i++)
    {
        if(!strcmp(cmds[i].name, args[0]))
            cmds[i].cmd(args[1]?&args[1]:NULL);
    }

    return 0;
}

 

Для расширения функциональности нужно просто дописывать функцию и добавлять ее в таблицу команд cmds[]

Пример разбора аргументов - в cmd_test, test2 - как пример второй команды.

В случае управляющего терминала видимо команда должна сразу выдавать результат работы в выходной буфер последовательного порта, поэтому вот так.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Для расширения функциональности нужно просто дописывать функцию и добавлять ее в таблицу команд cmds[]

Пример разбора аргументов - в cmd_test, test2 - как пример второй команды.

В случае управляющего терминала видимо команда должна сразу выдавать результат работы в выходной буфер последовательного порта, поэтому вот так.

 

спасибо. у меня команда без аргумента показывает текущее значение, с аргументом записывает новое. поэтому два указателя на функции чтения и записи.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

спасибо. у меня команда без аргумента показывает текущее значение, с аргументом записывает новое. поэтому два указателя на функции чтения и записи.

обработку можно как в самой команде сделать в if(!args), так и в цикле поиска команды по имени:

struct cmd {
    char* name;
    int (*cmd_read)(void);
    int (*cmd_write)(char** args);
};
...
int test_read(){ return 0; }
...
if(!strcmp(cmds[i].name, args[0]))
{
if(args[1])
   cmds[i].cmd_write(&args[1]);
else
   cmds[i].cmd_read();
}

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...