Объявление указателя функции - PullRequest
4 голосов
/ 09 июля 2020

Меня немного смущает учебник, который я использую, по сравнению с примерами, ответами SO и учебными пособиями, которые я нашел в Интернете.

Код из книги объявляет два указателя на функции, но никогда не назначает значение для них, и он не использует * в объявлении. Код работает нормально и компилируется без предупреждения, поэтому я немного запутался.

#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{   
    void    f(int), g(int);

    signal(SIGUSR1, f);
    signal(SIGUSR2, g);

    while(1)
        sleep(1);
}   

void f(int signum)
{   
    printf("Recieved signal %d: SIGUSR1\n", signum);
}   

void g(int signum)
{   
    printf("Received signal %d: SIGUSR2\n", signum);
    exit(SIGUSR2);
}   

Код, который я нашел в Интернете, выглядит примерно так, с синтаксисом указателя * и явным назначением адреса функции к указателям на функции:

#include <stdio.h> 

void fun(int a) 
{ 
    printf("Value of a is %d\n", a); 
} 
  
int main() 
{ 
    void (*fun_ptr)(int) = &fun; 
  
    (*fun_ptr)(10); 
  
    return 0; 
} 

Существует ли более одного правильного способа объявления указателя на функцию?

Почему работает код из книги?

Одна версия «правильнее», чем другая?

Ответы [ 2 ]

3 голосов
/ 09 июля 2020

void f(int), g(int); не объявляет указатели на функции *. Он объявляет две функции (f принимает int и возвращает void, и g принимает int и возвращает void).

(void (*f)(int), (*g)(int); объявляет соответствующие указатели функций и для этого действительно потребуется некоторая инициализация перед использованием.)

Объявление функций в области видимости блока немного сбивает с толку, потому что функции не могут быть локальными для блока.

По сути, это как если бы у вас было void f(int); void g(int); в области видимости файлов, за исключением того, что область видимости блока ограничивает область предварительных объявлений:

Пример:

void call_f(void)
{
    void f(int);
    f(42);
}

void call_f_again(void)
{
    void f(int); //need to redeclare unless there's also a global decl for f
    f(42);
}

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

  • void f(int) эквивалентно void (*f)(int) только тогда, когда оно используется как параметр функции. Это похоже на то, как int f[] в параметре функции эквивалентно int *f.
1 голос
/ 09 июля 2020

Это объявление

void    f(int), g(int);

объявляет две функции f и g в области видимости блока функции main. Их можно было объявить перед main, но автор кода решил объявить их в main, потому что они используются только в main. Значит, нет объявлений указателей на функции.

Кажется, вас смущает место, где объявлены функции.

Чтобы было понятнее, вы можете переписать программу следующим образом

#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>

void    f(int), g(int);

// or

void f(int);
void g(int);

int main(int argc, char *argv[])
{   
    signal(SIGUSR1, f);
    signal(SIGUSR2, g);

    while(1)
        sleep(1);
}   

void f(int signum)
{   
    printf("Recieved signal %d: SIGUSR1\n", signum);
}   

void g(int signum)
{   
    printf("Received signal %d: SIGUSR2\n", signum);
    exit(SIGUSR2);
}

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

Указатели функций, используемые в этих операторах

signal(SIGUSR1, f);
signal(SIGUSR2, g);

, неявно преобразованы на указатели на функции компилятором.

...