2010-11-08 15 views
12

De nos jours, je lisais le APUE.and j'ai trouvé la fonction définie comme ci-dessous:Comment comprendre cette définition

void (*signal(int signo, void (*func)(int)))(int); 

je suis confus, je sais que le signal est pointeur vers une fonction et le dernier (int) est son paramètre. je ne savais pas ce qui est (int signo, void (* func) (int)).

signaux
+1

Récupère 'cdecl'. Ça vous dira toutes ces choses. Je demande: 'expliquer void (* signal (int, void (*) (int))) (int);' et il répond: 'déclarer le signal en tant que fonction (int, pointeur sur la fonction (int) renvoyer void) renvoyer le pointeur function (int) retourner void' –

+0

essayer http://cdecl.org/ –

Répondre

23

La procédure générale : trouvez l'identifiant le plus à gauche et travaillez votre chemin. En l'absence d'un regroupement explicite avec des parenthèses, les opérateurs postfix tels que () et [] se lient avant les opérateurs unaires comme *; ainsi, les éléments suivants sont tout à fait vrai:

T *x[N]    -- x is an N-element array of pointer to T 
T (*x)[N]   -- x is a pointer to an N-element array of T 
T *f()    -- f is a function returning a pointer to T 
T (*f)()   -- f is a pointer to a function returning T 

L'application de ces règles à la déclaration, il se décompose comme

 signal          -- signal 
     signal(       )  -- is a function 
     signal( signo,     )  -- with a parameter named signo 
     signal(int signo,     )  -- of type int 
     signal(int signo,  func  )  -- and a parameter named func 
     signal(int signo,  *func  )  -- of type pointer 
     signal(int signo,  (*func)( ))  -- to a function 
     signal(int signo,  (*func)(int))  -- taking an int parameter 
     signal(int signo, void (*func)(int))  -- and returning void 
     *signal(int signo, void (*func)(int))  -- returning a pointer 
    (*signal(int signo, void (*func)(int)))( ) -- to a function 
    (*signal(int signo, void (*func)(int)))(int) -- taking an int parameter 
void (*signal(int signo, void (*func)(int)))(int); -- and returning void 

En bref, signal renvoie un pointeur vers une fonction renvoyant void. signal prend deux paramètres: un entier et un pointeur vers une autre fonction retournant void.

Vous pouvez utiliser typedefs pour faciliter la lecture (et la page de manuel pour signal sur Ubuntu linux ne fait que cela); cependant, je pense qu'il est utile de montrer la version non-typedef'd pour démontrer exactement comment fonctionne la syntaxe. La facilité de typedef est merveilleuse, mais vous devez vraiment comprendre comment les types sous-jacents fonctionnent afin de l'utiliser efficacement. La fonction signal configure un gestionnaire de signaux; le deuxième argument est la fonction qui doit être exécutée si un signal est reçu. Un pointeur vers le gestionnaire de signal en cours (le cas échéant) est renvoyé.

Par exemple, si vous voulez que votre programme pour gérer des signaux d'interruption (tels que de Ctrl-C):

static int g_interruptFlag = 0; 

void interruptHandler(int sig) 
{ 
    g_interruptFlag = 1; 
} 

int main(void) 
{ 
    ... 
    /** 
    * Install the interrupt handler, saving the previous interrupt handler 
    */ 
    void (*oldInterruptHandler)(int) = signal(SIGINT, interruptHandler); 

    while (!g_interruptFlag) 
    { 
    // do something interesting until someone hits Ctrl-C 
    } 

    /** 
    * Restore the previous interrupt handler (not necessary for this particular 
    * example, but there may be cases where you want to swap out signal handlers 
    * after handling a specific condition) 
    */ 
    signal(SIGINT, oldInterruptHandler); 
    return 0; 
} 

EDIT Je tendis l'exemple de code pour signal à quelque chose qui est je l'espère plus d'illustration.

+1

+1 pour une réponse merveilleuse! – Shrayas

16
void (*signal(int signo, void (*func)(int)))(int); 

est fonction qui prend int et un pointeur de fonction prenant int et le retour vide et renvoie un pointeur de fonction int prise et le retour vide. C'est,

typedef void(*funcPtr)(int) 

alors nous avons

funcPtr signal(int signo, funcPtr func); //equivalent to the above 

La syntaxe est en effet étrange, et ces choses mieux se faire avec un typedef. À titre d'exemple, si vous voulez déclarer une fonction qui prend un int et renvoie un pointeur vers une fonction qui prend l'omble chevalier et restituant le double sera

double (*f(int))(char); 

Edit: après un commentaire qui lit « Oooullaaa », je Je donne un autre exemple qui est plus "woooow" :)

Nous allons déclarer une fonction qui prend
1. un pointeur sur un tableau de 5 pointeurs vers des fonctions prenant chacune un flottant et renvoyant le double.
2. un pointeur sur un tableau de 3 ponters vers des tableaux de 4 entrées
et renvoie un pointeur sur la fonction qui prend un pointeur pour fonctionner en prenant int et en renvoyant un pointeur vers une fonction prenant float et retournant void et retournant un entier non signé.

La solution typedef serait ceci:

typedef double (*f1ptr) (float); 
typedef f1ptr (*arr1ptr)[5]; 
typedef int (*arr2ptr)[4]; 
typedef arr2ptr (*arr3ptr)[3]; 
typedef void(*f2Ptr)(float); 
typedef f2ptr (*f3ptr)(int); 
typedef unsigned int (*f4ptr) (f3ptr); 
f4ptr TheFunction(arr1ptr arg1, arr3ptr arg2); 

Maintenant, le plus drôle :) Sans typedefs ce sera:

unsigned int (*TheFunction(double (*(*)[5])(float), int(*(*)[3])[4]))(void(*(*)(int))(float)) 

Mon dieu, que je viens d'écrire cela? :)

+2

Wooooooooooooow – valdo

+0

@valdo: voir mon édition pour un pire wooooow :) –

+0

Drôle? La version non-typedef'd est * parfaitement * transparente. –

12

La règle en spirale dans le sens horaire aidera: http://c-faq.com/decl/spiral.anderson.html

Il y a trois étapes simples à suivre:

À partir de l'élément inconnu, se déplacer dans une direction spirale/horaire; lorsque ecountering les éléments suivants pour les remplacer par les états correspondants anglais:

[X] ou [] => array taille X ... ou matrice de taille définie à ...

(type 1, type 2) = > fonction passant type1 et type2 retour ...

  • => pointeur (s) à ...

continuer à faire cela dans une direction spirale/droite jusqu'à ce que tous les jetons ont été couverts. Toujours résoudre tout ce qui entre parenthèses en premier!

Voir « Exemple # 3: Le « Ultimate » », qui est à peu près exactement ce que vous demandez:

le signal

» est une fonction qui passe un int et un pointeur vers une fonction qui passe un int rien de retour (vide) renvoyant un pointeur vers une fonction qui passe un entier de ne rien renvoyer (vide) »

+0

C'est une si belle ressource. Merci ! – Shrayas

0

Installation cdecl pour votre distribution (si disponible) ou aller here

Sinon, je crois que la réponse de Armen Tsirunyan est correcte.

3

Si vous n'avez pas accès à cdecl en ce moment, voici la sortie cdecl:

$ cdecl 
cdecl> explain void (*signal(int , void (*)(int)))(int); 
declare signal as function (int, pointer to function (int) returning void) returning pointer to function (int) returning void