реклама на сайте
подробности

 
 
> передача указателя на функцию в функцию
Jurdens
сообщение Nov 8 2007, 13:39
Сообщение #1


Частый гость
**

Группа: Свой
Сообщений: 107
Регистрация: 9-07-05
Пользователь №: 6 656



Какие спец эффекты можно ожидать при преобразовании типов указателей на функцию
В параметрах функции.

Например определим тип указатель на функцию с одним параметром типа указатель на неопределенный тип , функция ничего не возвращает
typedef void (*CPU_FNCT_PTR)(void *);
и тип указатель на функцию
typedef void (*CPU_FNC)(char);

void func2(char ParF2 );
char Data;
func1( void (* Fnc_par)(void *),void * ptrPar);

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

Передадим указатель на функцию func2 как параметр func1 (приведя ее к типу CPU_FNCT_PTR) и передадим указатель на переменную Data как второй параметр приведя ее к типу void * ;.
Получится такой вызов
func1( (CPU_FNCT_PTR) func2, ( void *)Data);

…….

func1( void (* Fnc_par)(void *),void * ptrPar)
{
*Fnc_par( * ptrPar); // Сработает func2 ? или
// надо преобразовать
*((CPU_FNC ) Fnc_par) ( ( сhar*) ptrPar);
};

А хотелось бы просто указатель на произвольную функцию и ее аргумент тип которого заранее неизвестен
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов (1 - 12)
Николай Z
сообщение Nov 8 2007, 14:21
Сообщение #2


Местный
***

Группа: Участник*
Сообщений: 418
Регистрация: 20-08-07
Пользователь №: 29 930



Цитата(Jurdens @ Nov 8 2007, 16:39) *
Какие спец эффекты можно ожидать при преобразовании типов указателей на функцию
В параметрах функции.

Например определим тип указатель на функцию с одним параметром типа указатель на неопределенный тип , функция ничего не возвращает
typedef void (*CPU_FNCT_PTR)(void *);
и тип указатель на функцию
typedef void (*CPU_FNC)(char);

void func2(char ParF2 );
char Data;
func1( void (* Fnc_par)(void *),void * ptrPar);

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

Передадим указатель на функцию func2 как параметр func1 (приведя ее к типу CPU_FNCT_PTR) и передадим указатель на переменную Data как второй параметр приведя ее к типу void * ;.
Получится такой вызов
func1( (CPU_FNCT_PTR) func2, ( void *)Data);

…….

func1( void (* Fnc_par)(void *),void * ptrPar)
{
*Fnc_par( * ptrPar); // Сработает func2 ? или
// надо преобразовать
*((CPU_FNC ) Fnc_par) ( ( сhar*) ptrPar);
};

А хотелось бы просто указатель на произвольную функцию и ее аргумент тип которого заранее неизвестен


Ну а кто Вам мешает описать еще несколько функций описать так же как func2 и передавать их в func1?
Ведь в описании func1 - у Вас нет ни слова про то, что ей годится только fun2 - не так ли?

По-моему все сработает, если Вы вот так запишете:

func1( (CPU_FNCT_PTR) function, ( void *)Data);

…….

func1( (CPU_FNCT_PTR) function, ( void *)Data)
{
function(Data);
};

Причем сработает для любой функции(func2, func3, func4 ...), если все они будут описаны так же как func2. Что передадите в func1 - то из нее и будет вызвано...

Сообщение отредактировал Николай Z - Nov 8 2007, 14:22
Go to the top of the page
 
+Quote Post
Непомнящий Евген...
сообщение Nov 9 2007, 06:21
Сообщение #3


Знающий
****

Группа: Свой
Сообщений: 771
Регистрация: 16-07-07
Из: Волгодонск
Пользователь №: 29 153



Когда вы вызываете функцию, компилятору надо знать типы передаваемых параметров и тип возвращаемого значения, чтобы расположить все это на стеке и в регистрах нужным образом.
Если вызвать функцию void func(char t), используя указатель void (*P)(void*), то что из этого получится будет целиком зависеть от реализации компилятора. Например, если аргументы передаются в стеке и функция должна их выбрать сама, то будет плохо.
Тут второй вопрос - а зачем вам это надо? Что значит - передать аргумент неизвестного типа? Максимум - это указатель void*... Но смешивать указатель и char, как в вашем примере - ИМХО, прямой путь поиметь кучу траблов.
Go to the top of the page
 
+Quote Post
scifi
сообщение Nov 9 2007, 07:00
Сообщение #4


Гуру
******

Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136



Цитата(Непомнящий Евгений @ Nov 9 2007, 09:21) *
Когда вы вызываете функцию, компилятору надо знать типы передаваемых параметров и тип возвращаемого значения, чтобы расположить все это на стеке и в регистрах нужным образом.
Если вызвать функцию void func(char t), используя указатель void (*P)(void*), то что из этого получится будет целиком зависеть от реализации компилятора. Например, если аргументы передаются в стеке и функция должна их выбрать сама, то будет плохо.
Тут второй вопрос - а зачем вам это надо? Что значит - передать аргумент неизвестного типа? Максимум - это указатель void*... Но смешивать указатель и char, как в вашем примере - ИМХО, прямой путь поиметь кучу траблов.

Поддерживаю. Можно, конечно, извратиться, но это будет коряво и непереносимо. Вы лучше изложите задачу, и я уверен, что кто-нибудь предложит более элегантное решение.
Go to the top of the page
 
+Quote Post
Jurdens
сообщение Nov 9 2007, 08:26
Сообщение #5


Частый гость
**

Группа: Свой
Сообщений: 107
Регистрация: 9-07-05
Пользователь №: 6 656



Цитата(scifi @ Nov 9 2007, 10:00) *
Поддерживаю. Можно, конечно, извратиться, но это будет коряво и непереносимо. Вы лучше изложите задачу, и я уверен, что кто-нибудь предложит более элегантное решение.


А задача такая запускать произвольную функцию по таймеру через время
Time. У запускаемой функции неизвестен тип параметра (так надо ) в общем случае и возвращаемый параметр
для этого мы должны передать ее адрес в функцию.
DelayStart(unsigned Time, *Func(?));

Подумал в С++ есть механизм передачи по ссылке F(&data1,&Func1) может тут как то поэксперементировать?
Go to the top of the page
 
+Quote Post
alexander55
сообщение Nov 9 2007, 09:09
Сообщение #6


Бывалый
*****

Группа: Свой
Сообщений: 1 584
Регистрация: 7-08-07
Пользователь №: 29 615



Цитата(Jurdens @ Nov 9 2007, 11:26) *
А задача такая запускать произвольную функцию по таймеру через время
Time.

Произвольную функцию, но она д.б. известна когда:
- на этапе компиляции
- на этапе выполнения.

Цитата(Jurdens @ Nov 9 2007, 11:26) *
У запускаемой функции неизвестен тип параметра (так надо )

Т.е. на этапе выполнения параметр известен, так ?

Цитата(Jurdens @ Nov 9 2007, 11:26) *
У запускаемой функции неизвестен ... и возвращаемый параметр

У запускаемой функции возвращаемый параметр известен всегда. sad.gif

Цитата(Jurdens @ Nov 9 2007, 11:26) *
Подумал в С++ есть механизм передачи по ссылке F(&data1,&Func1) может тут как то поэксперементировать?

В С и С++ есть передача параметра по значению (по умолчанию) и по ссылке.

PS. Я не понимаю, Вы решаете конкретную задачу или теоретик на досуге ? smile.gif
Go to the top of the page
 
+Quote Post
Николай Z
сообщение Nov 9 2007, 09:36
Сообщение #7


Местный
***

Группа: Участник*
Сообщений: 418
Регистрация: 20-08-07
Пользователь №: 29 930



Цитата(Непомнящий Евгений @ Nov 9 2007, 09:21) *
Когда вы вызываете функцию, компилятору надо знать типы передаваемых параметров и тип возвращаемого значения, чтобы расположить все это на стеке и в регистрах нужным образом.
Если вызвать функцию void func(char t), используя указатель void (*P)(void*), то что из этого получится будет целиком зависеть от реализации компилятора. Например, если аргументы передаются в стеке и функция должна их выбрать сама, то будет плохо.
Тут второй вопрос - а зачем вам это надо? Что значит - передать аргумент неизвестного типа? Максимум - это указатель void*... Но смешивать указатель и char, как в вашем примере - ИМХО, прямой путь поиметь кучу траблов.


И не только от реализации компилятора будет зависеть результат... Но так же еще и от специфики архитектуры процессора тоже будет зависеть. Мне не хотелось тут просто этого касаться...

Но я согласен с тем, что поставленная в топе задача - достаточно надуманная или выковырянная из левой ноздри. Таких гарантированных общих решений обычно не бывает. Нужно знать конкретику ибо решение таких вещей "в общем" - это будет практически попытка переноса идеи "виртуальной функции" в термины С, которая для С как бы не совсем естественна. Можно же еще захотеть решить задучу вызова любой функции с любым списком параметров тоже... И заставить потом объектный код во всем этом разбираться, но вот зачем такие навороты и чего ради - совершенно неясно.

Неясна цель и неопределена расплата за такую универсальность. Гонка за чрезмерной универсальностью - это либо недопонимание задачи, либо некий фанатизм. А вот реальная задача - всегда гораздо понятнее...

Цитата(Jurdens @ Nov 9 2007, 11:26) *
А задача такая запускать произвольную функцию по таймеру через время
Time. У запускаемой функции неизвестен тип параметра (так надо ) в общем случае и возвращаемый параметр
для этого мы должны передать ее адрес в функцию.
DelayStart(unsigned Time, *Func(?));

Подумал в С++ есть механизм передачи по ссылке F(&data1,&Func1) может тут как то поэксперементировать?


Первый вопрос - а зачем надо неизвестный тип параметра? Я почти уверен, что практически всегда можно свести параметры всех вызываемых функций к одному типу... Ниже скажу как...

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

В Вашем случае у всех вызываеммых функций вполне можно свести параметры просто к указателю на структуры, которые будут иметь разную струтуру, но передавать можно просто Pointer на них, а любая ваша функция знает с какой именно структурой она работает. Вот вам уже и тип параметра - всегда один и тот же - просто указатель void и никаких разнотипных параметров... Ну и получится, что если у funct1 - cтруктура эта массив char symb[10] - то пусть его функция funct1 и знает а для вызываеющей функции это просто указатель &symb, для функции funct2 - параметр некая струтура Struct - общего вида, но вызывающей функции передается опять же только адрес этой структуры &Struct и ничего более... Может и коряво изложил - но суть примерно такая... И нету уже никаких передач параметров разных типов для вызывающей функции... biggrin.gif

Другой вопрос - насколько это будет универсально, мобильно и т.д. и т.п.

Сообщение отредактировал Николай Z - Nov 9 2007, 09:44
Go to the top of the page
 
+Quote Post
Непомнящий Евген...
сообщение Nov 9 2007, 10:27
Сообщение #8


Знающий
****

Группа: Свой
Сообщений: 771
Регистрация: 16-07-07
Из: Волгодонск
Пользователь №: 29 153



Цитата(Jurdens @ Nov 9 2007, 11:26) *
А задача такая запускать произвольную функцию по таймеру через время
Time. У запускаемой функции неизвестен тип параметра (так надо ) в общем случае и возвращаемый параметр
для этого мы должны передать ее адрес в функцию.
DelayStart(unsigned Time, *Func(?));


Тогда вопрос - там, откуда будет вызвана эта самая Func, необходимо ей что-то передать. И откуда это что-то возьмется? И куда ляжет результат выполнения Func?
Т.е. мы приходим к чему-то типа:
Код
typedef void*(*unifunc)(void *)
void DelayStart(unsigned Time, unifunc func, void *arg, void **res);

...

void *f1(void * arg)
{
  TMyStruct *a = (TMyStruct *)arg;
  TMyStruct *res;
  ....
  return res;
}

void main()
{
  TMyStruct a, *b;
  DelayStart(100, f1, &a, &b);
...
}
Go to the top of the page
 
+Quote Post
Jurdens
сообщение Nov 9 2007, 10:40
Сообщение #9


Частый гость
**

Группа: Свой
Сообщений: 107
Регистрация: 9-07-05
Пользователь №: 6 656



В С и С++ есть понятие указателя на неопределенный тип (*void) который можно
преобразовать (типизировать) под любой тип данных.
, понятие указателя на функцию.
а зачем ?
когда можно использовать 255 конструкций if else
или 16 switch case в которые вложены
еще 16 switch case
Иногда при разработке пишут несколько человек и один ставит другому
задачу вот моя такая написать функцию которая вызывает функцию
а какую это определяется динамикой работы всего устройства в процессе его работы
некий пользователь нажимает кнопочки и при этом надо выполнять одни функции
изменяются показания датчиков ,которые опрашивает устройство, надо, выполнять другие у которых есть аргументы и еще и разные.
Этим всем занимается другой человек.
Просто лишний раз неохота его беспокоить и с другой стороны интересно сталкивались ли другие с подобными задачами.
Можно конечно сказать примерно тоже что на этом форуме типа
Цитата
ты определись какие функции
будешь вызывать на этапе компиляции
и немороч мне голову.
Но это не корректно потому что такие приемы применяют и они работают ,
например в при написании операционок. Обещали их прислать.
Цитата
У вас есть халатик с перламутровыми пуговицами? .... А за чем вам? Может вам и этот подойдет
Go to the top of the page
 
+Quote Post
alexander55
сообщение Nov 9 2007, 10:53
Сообщение #10


Бывалый
*****

Группа: Свой
Сообщений: 1 584
Регистрация: 7-08-07
Пользователь №: 29 615



Цитата(Jurdens @ Nov 9 2007, 13:40) *

Я понял Ваши проблемы. Вам надо оговорить интерфейсы функций со смежниками (API интерфейс).
Тяжело ходить туда - не зная, куда и приносить то - не зная, что.
Могу только посочуствовать. 05.gif
Go to the top of the page
 
+Quote Post
Непомнящий Евген...
сообщение Nov 9 2007, 11:10
Сообщение #11


Знающий
****

Группа: Свой
Сообщений: 771
Регистрация: 16-07-07
Из: Волгодонск
Пользователь №: 29 153



Цитата(Jurdens @ Nov 9 2007, 13:40) *
...
задачу вот моя такая написать функцию которая вызывает функцию
а какую это определяется динамикой работы всего устройства в процессе его работы


Язык не имеет средств вызвать функцию с неизвестной на этапе компиляции сигнатурой.
Имхо, проще всего в этой ситуации потребовать, чтобы все такие функции обладали заранее установленной сигнатурой. К примеру: int func(int m1, int m2, void *p) - что то типа того, как сделаны функции сообщений в winapi.

Вдогонку:
Цитата(Jurdens @ Nov 9 2007, 13:40) *
В С и С++ есть понятие указателя на неопределенный тип (*void) который можно
преобразовать (типизировать) под любой тип данных.

не под "любой тип данных", а под "указатель любого типа"...
Go to the top of the page
 
+Quote Post
Николай Z
сообщение Nov 9 2007, 11:59
Сообщение #12


Местный
***

Группа: Участник*
Сообщений: 418
Регистрация: 20-08-07
Пользователь №: 29 930



Цитата(Jurdens @ Nov 9 2007, 13:40) *
В С и С++ есть понятие указателя на неопределенный тип (*void) который можно
преобразовать (типизировать) под любой тип данных.
, понятие указателя на функцию.
а зачем ?
когда можно использовать 255 конструкций if else
или 16 switch case в которые вложены
еще 16 switch case
Иногда при разработке пишут несколько человек и один ставит другому
задачу вот моя такая написать функцию которая вызывает функцию
а какую это определяется динамикой работы всего устройства в процессе его работы
некий пользователь нажимает кнопочки и при этом надо выполнять одни функции
изменяются показания датчиков ,которые опрашивает устройство, надо, выполнять другие у которых есть аргументы и еще и разные.
Этим всем занимается другой человек.
Просто лишний раз неохота его беспокоить и с другой стороны интересно сталкивались ли другие с подобными задачами.
Можно конечно сказать примерно тоже что на этом форуме типа и немороч мне голову.
Но это не корректно потому что такие приемы применяют и они работают ,
например в при написании операционок. Обещали их прислать.


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

Вот если бы такая проработка была сделана - то никакой проблемы с "неопределенными" типами параметров просто не существовало даже если вызываемых функций было бы даже не 256 а 1024 или 4096... Да и такой Case - размерностью 16x16 - врядли бы понадобился... Просто похоже что Ваш проект вообще делается без какой-либо предварительной проработки... И вообще непонятно - что значит "не беспокоить" коллегу или руководителя, если есть непонятки в архитектуре того, что вы делаете? Он у Вас что - небожитель или все-таки участник проекта?

Нормальный подход к разработке таков, что в случае надобности не надо стесняться и Генерального Директора дернуть за известное место и не один раз - если это нужный и важный для предприятия проект...
Go to the top of the page
 
+Quote Post
Oldring
сообщение Nov 13 2007, 14:25
Сообщение #13


Гуру
******

Группа: Свой
Сообщений: 3 041
Регистрация: 10-01-05
Из: Москва
Пользователь №: 1 874



Цитата(Jurdens @ Nov 9 2007, 13:40) *
Можно конечно сказать примерно тоже что на этом форуме типа и немороч мне голову.
Но это не корректно потому что такие приемы применяют и они работают ,
например в при написании операционок. Обещали их прислать.


Применяют. Работают. Просто для передачи указателя на функцию. Тип функции при этом передается отдельно и потом интерпретируется при вызове smile.gif. Только все это implementation defined.
Ну сами задумайтесь: функция хочет каких-то аргументов на стеке - и кто их туда положит, если в точке вызова вообще не известно, какие функция хочет аргументы?

Если нужно вызывать функцию по таймеру - нужно в C создать функцию одного типа, например, void (*FPTR)( void* );, и передавать функции регистрации для таймера этот указатель и один аргумент - в зависящую от функции структуру, в которую будут положеты параметры функции. В плюсах такое лучше сделать абстрактным классом с одной чисто виртуальной функцией типа void f(); который будет вызываться таймером, и потомки будут реализовывать эту функцию и хранить параметры.


--------------------
Пишите в личку.
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 22nd July 2025 - 10:58
Рейтинг@Mail.ru


Страница сгенерированна за 0.01477 секунд с 7
ELECTRONIX ©2004-2016