Как вызвать функцию по указателю в C
Я просматривал библиотеку USB Atmel для AT91SAM7, и я кое-что не понимаю. Конечная точка - это структура, определяемая следующим образом:
typedef struct {
volatile unsigned char state;
volatile unsigned char bank;
volatile unsigned short size;
Transfer transfer; //thus Endpoint contains an instance of "Transfer"
} Endpoint
точка; А сама передача представляет собой следующую структуру:
typedef struct {
char *pData;
volatile int buffered;
volatile int transferred;
volatile int remaining;
volatile TransferCallback fCallback;
void *pArgument;
} Transfer;
А TransferCallback - это функция со следующим прототипом:
typedef void (*TransferCallback)(void *pArg, unsigned char status, unsigned int transferred, unsigned int remaining);
также два указателя были определены как следующие:
Endpoint *pEndpoint = &(endpoints[bEndpoint]);
Transfer *pTransfer = &(pEndpoint->transfer);
Я хочу знать, почему такой способ вызова функции TransferCallback действителен:
((TransferCallback) pTransfer->fCallback) (followed by the required arguments passed )
Но это не верно
((TransferCallback)pEndpoint->transfer->fCallback)?
Как я мог напрямую вызвать TransferCallback без использования указателя, такого как pTransfer между ними? Я попробовал несколько комбинаций, но ни одна из них не сработала.
2 ответа
Обратите внимание, что Endpoint
нет указателя на элемент Transfer (*Transfer
), но член передачи. В терминах машин, а не одно слово памяти в каждом Endpoint
используется в качестве указателя на Transfer
, все поля Transfer
член хранятся непосредственно в памяти, выделенной для Endpoint
,
Чтобы перейти к преследованию, вам нужно:
((TransferCallback)pEndpoint->transfer.fCallback)
Относительно заголовка к OP: как вызвать функцию по указателю в C
+1 к ответу Алекса на ваш вопрос о том, как, но есть еще один момент, который может быть сделан для того, чтобы знать, почему стоит выбрать указатель на функцию, просто указав имя обычной функции; Указатели на функции особенно полезны в C* (см. *), Когда у вас есть набор функций, которые похожи в том, что они содержат один и тот же список аргументов, но имеют разные выходные данные. Вы можете определить массив указателей на функции, упрощая, например, вызов функций в этом семействе из коммутатора или из цикла, или при создании ряда потоков в пуле, которые содержат аналогичные рабочие функции в качестве аргументов. Вызов массива упрощает изменение индекса указателя, чтобы получить определенную функциональность, необходимую для каждого уникального случая.
В качестве простого примера, две строковые функции strcat()
а также strcpy()
есть список аргументов: (char *, const char *)
следовательно, может быть назначен массив указателей на функции. Сначала создайте массив указателей на функции:
char * (*pStr[2])( char *a, const char *b);` //array of function pointers pStr[]
Затем сделайте присвоения strcat и strcpy массиву:
void someFunc(void)
{
pStr[0] = strcat; //assign strcat to pointer [0]
pStr[1] = strcpy; //assign strcpy to pointer [1]
}
Сейчас, strcat()
или же strcpy()
можно назвать как:
int main(void)
{
char a[100]="kjdhlfjgls";
char b[100]="kjdhlfjgls";
someFunc();//define function pointers
pStr[0](a, "aaaaaaaa"); //strcat
pStr[1](b, "aaaaaaaa"); //strcpy
return 0;
}
Пример вывода:
Это всего лишь простой пример. Он не рассматривает всю степень полезности, которую могут предоставить указатели на функции, но иллюстрирует другую причину, по которой указатели на функции могут быть предпочтительнее в некоторых ситуациях.
* Эта иллюстрация нацелена только на C, в отличие от C++, где качества наследования и полиморфизма, присущие этому языку, сделали бы это предложение ненужным.