Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Функция, которая возвращает указатель на саму себя
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Cредства разработки для МК > IAR
Александр Куличок
Как в С описать функцию, которая возвращает указатель на функцию, себе подобную (на саму себя)?

В Делфи, например, можно сначала описАть указатель на тип, а потом описать уже сам тип:
type
PFunc = ^TFunc;
TFunc = function(X: Integer): PFunc;

Позволяет ли подобное С и как это реализуется?
shreck
Хм...
Интересно, а для чего это нужно, если не секрет?
zltigo
Цитата(Александр Куличок @ Apr 10 2007, 11:25) *
Позволяет ли подобное С и как это реализуется?

Я вообще не понимаю, в чем проблема-то может быть? Описывайте и возвращайте любые указатели.
xemul
"То бензин, а то дети..." (это я про Дельфи и Сиsmile.gif)
Товарищу, вероятно, просто пример нужен.
Вы, уважаемый zltigo, уже как-то постили простенькую расталдычку для начинающих про указатели и скобки - ссылку на нее прибить бы вверху всех форумов, где потенциально могут спрашивать про Сиsmile.gif.

Функция, ничего не получающая и не возвращающая:
void foo(void);

Указатель на функцию, ничего не получающую и не возвращающую:
void (void)* fptr;

Функция, получающая указатель на функцию, ничего не получающую и ничего не возвращающую, и его же возвращающая:
void (void)* foo(void (void)*);

Соответственно, имплементация
void (void)* foo(void (void)* fptr)
{
return fptr;
}

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

UPD:
т.е. достаточно:
void foo(void);
void (void)* fptr;

fptr = &foo;
Александр Куличок
Как возвращать указатель на функцию, которая ничего не возвращает, я знаю.
Мне нужно немного другое. Возвращать нужно не ЛЮБОЙ указатель, а именно указатель на функцию,
себе подобную. То есть получается как бы рекурсия в объявлении типа.
Объясню на примере:

typedef
??????? // здесь обьявляется funcPtrType

extern char RxByte(void); // читает байт из UART

funcPtrType StartFunc(char Abyte) // фукнция обработки данных №1
funcPtrType Rx1Func(char Abyte); // фукнция обработки данных №2
funcPtrType Rx2Func(char Abyte); // фукнция обработки данных №3
funcPtrType EndFunc(char Abyte); // фукнция обработки данных №4



//**************************************
// прерывание приема данных по UART
//**************************************
viod UART_RX(void){
char RxByte;
static funcPtrType funcPtr; // хранит указатель на текущую фукнцию обработки принятого байта

RxByte = UDR;
if (funcPtr == NULL) funcPtr = &StartFunc;



funcPtr = (*funcPtr)(RxByte); //обрабатываем принятий байт и возвращаем указатель
// на функцию, которая будет вызвана в следующий раз

}


//**************************************
funcPtrType Rx1Func(char Abyte)
{
.... // обрабатываем Abyte
if (Abyte != 0x01) return &Rx1Func; // при следующеем приеме возвращаемся в эту же функцию
else return &EndFunc; //

}

//**************************************
funcPtrType Rx2Func(char Abyte)
{
.... // обрабатываем Abyte
if (Abyte != 0x01) return &Rx1Func; // при следующеем приеме возвращаемся в эту же функцию
else return &EndFunc; //

}
//**************************************
funcPtrType EndFunc(char Abyte)
{
if (Abyte =='A') return &Rx1Func;
if (Abyte == 'B') return &Rx2Func;
return NULL;
}
//**************************************
funcPtrType StartFunc(char Abyte)
{
if (Abyte ==0x01) return &Rx1Func;
if (Abyte ==0x02) return &Rx2Func;
return NULL;
}

Можно, конечно, объявить funcPtr как глобальную, и в фукнциях обработки данных (StartFunc, EndFunc, Rx1Func, Rx2Func) напрямую присваивать ей значения. Но такой подход меня пока не устраивает.
rezident
Может я не совсем понял сути проблемы, но почему бы вам не передавать указатель указателя функции?
shreck
Цитата(Александр Куличок @ Apr 10 2007, 19:18) *
Как возвращать указатель на функцию, которая ничего не возвращает, я знаю.
Мне нужно немного другое. Возвращать нужно не ЛЮБОЙ указатель, а именно указатель на функцию,
себе подобную. То есть получается как бы рекурсия в объявлении типа.
Объясню на примере:

typedef
??????? // здесь обьявляется funcPtrType

extern char RxByte(void); // читает байт из UART

funcPtrType StartFunc(char Abyte) // фукнция обработки данных №1
funcPtrType Rx1Func(char Abyte); // фукнция обработки данных №2
funcPtrType Rx2Func(char Abyte); // фукнция обработки данных №3
funcPtrType EndFunc(char Abyte); // фукнция обработки данных №4

...



Я бы рекомендовал пересмотреть дизайн этой части программы. Слишком уж он хитромудрый.
Но если не хочется, то может быть использовать массив указателей на функцию возвращающую, скажем uint8, который будет являтся индексом в массиве указателей. Приведенный код практически не изменится.
YemZ
typedef void* (*funcPtrType)(char);

т.е. funcPtrType – это указатель на функцию, принимающую байт и возвращающую бестиповый указатель

Возвраты из функций обработки должны выглядеть так
return (funcPtrType)&Rx1Func;

Выделенная строка тоже обзаведется приведением типа
funcPtr = (funcPtrType)((*funcPtr)(RxByte));


Кстати такие варианты тоже верны:
return (funcPtrType)Rx1Func;
funcPtr = (funcPtrType)(funcPtr(RxByte));
Александр Куличок
Цитата(shreck @ Apr 10 2007, 15:05) *
Я бы рекомендовал пересмотреть дизайн этой части программы. Слишком уж он хитромудрый.
Но если не хочется, то может быть использовать массив указателей на функцию возвращающую, скажем uint8, который будет являтся индексом в массиве указателей. Приведенный код практически не изменится.


Это тоже оди из выходов, но не совсем то, чего хотелось бы. Очень не хочется привязывать имена функций к цифрам. А хитромудрость на самом деле кажущаяся. Дело в том, что подобных функций-обработчиков будет не одна даже не 10, а штук под 50. Они будут размещаться в разных модулях (своя цепочка обработчиков - в своем модуле) и обрабатывать каждая свою последовательность данных (которые поступают по УАРТ) - т.е реализовывать свой протокол. При этом должна быть возможность легко добавлять в программу дополнительные протоколы.
zltigo
Цитата(Александр Куличок @ Apr 10 2007, 13:18) *
Возвращать нужно не ЛЮБОЙ указатель, а именно указатель на функцию,

Читать я все это не стал, извините, обсуждать архитктуру - тоже. Но "любой" преобразуется в нужный при использовании спокойно:
Код
void *dummy_func(void)
{
    return( (void *)dummy_func );    
}

void main(void)
{    
      ((void *(*)(void))dummy_func())();

}
Александр Куличок
Цитата(YemZ @ Apr 10 2007, 15:29) *
typedef void* (*funcPtrType)(char);

т.е. funcPtrType – это указатель на функцию, принимающую байт и возвращающую бестиповый указатель

Возвраты из функций обработки должны выглядеть так
return (funcPtrType)&Rx1Func;

Выделенная строка тоже обзаведется приведением типа
funcPtr = (funcPtrType)((*funcPtr)(RxByte));
Кстати такие варианты тоже верны:
return (funcPtrType)Rx1Func;
funcPtr = (funcPtrType)(funcPtr(RxByte));


БОЛЬШОЕ СПАСИБО. Это то, что мне надо. Еще хотелось бы узнать - цепочки данных (деревья) в С реализуются точно так же? (Там аналогичная задача при описании структуры - она должна содержать ссылку на саму себя)
Сергей Борщ
Цитата(Александр Куличок @ Apr 10 2007, 14:57) *
Еще хотелось бы узнать - цепочки данных (деревья) в С реализуются точно так же?
Кажется вопрос деревьев (связанных списков) рассматривается в любой книжке по C smile.gif
Код
struct my_struct
{
   my_struct *prev;
   my_struct *next;
  ........
}
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.