2010-11-08 11 views
12

Heute definieren zu verstehen, ich war der APUE.and Lesen fand ich die Funktion, wie unten definiert:Wie diese

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

i war verwirrt, ich weiß Signal Zeiger auf eine Funktion ist und die letzte (int) ist sein Parameter. ich wusste nicht, was ist (int signo, void (* func) (int)).

+1

Get 'cdecl'. Es wird dir all diese Dinge erzählen. Ich frage: 'explain void (* signal (int, void (*) (int))) (int);' und es antwortet: 'deklariere das Signal als Funktion (int, Zeiger auf Funktion (int) gibt void zurück) Funktion (int) Rückgabe void –

+0

versuchen http://cdecl.org/ –

Antwort

23

Das allgemeine Verfahren : Finde den am weitesten links liegenden Identifikator und arbeite dich raus. Wenn eine explizite Gruppierung mit Klammern fehlt, binden Postfixoperatoren wie () und [] vor unären Operatoren wie *; damit die folgenden Aussagen wahr sind:

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 

diese Regeln auf die Erklärung Auftragen, es setzt sich wie

 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 

Kurz gesagt, signal gibt einen Zeiger auf eine Funktion Rückkehr void. signal benötigt zwei Parameter: eine Ganzzahl und einen Zeiger auf eine andere Funktion, die void zurückgibt.

Sie könnten typedefs verwenden, um dies einfacher zu lesen (und die man-Seite für signal auf Ubuntu Linux tut genau das); Ich denke jedoch, dass es wertvoll ist, die nicht-typedef-Version zu zeigen, um genau zu demonstrieren, wie die Syntax funktioniert. Die Typdef-Einrichtung ist wunderbar, aber Sie müssen wirklich verstehen, wie die zugrunde liegenden Typen funktionieren, um sie effektiv zu nutzen.

Die signal-Funktion richtet einen Signal-Handler ein; Das zweite Argument ist die Funktion, die ausgeführt werden soll, wenn ein Signal empfangen wird. Ein Zeiger auf den aktuellen Signalhandler (falls vorhanden) wird zurückgegeben.

Zum Beispiel, wenn Sie Ihr Programm wollen Interrupt-Signale zu verarbeiten (wie von 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 I erweitert den Beispielcode für signal auf etwas, das hoffentlich mehr illustrativ ist.

+1

+1 für eine wunderbare Antwort! – Shrayas

16

Signal ist eine Funktion, die int und einen Zeiger zur Funktion nimmt, die int und void zurücknimmt und einen Funktionszeiger zurückgibt, der int und void zurückgibt. Das heißt,

typedef void(*funcPtr)(int) 

dann haben wir

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

Die Syntax ist in der Tat merkwürdig, und solche Dinge besser mit einem typedef erfolgen. Als Beispiel, wenn Sie eine Funktion deklarieren möchten, die einen int und gibt einen Zeiger auf eine Funktion char Doppel wird

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

bearbeiten und Rückkehr nehmen nimmt: nach einem Kommentar, der „Wooooooow“ liest, ich bin ein anderes Beispiel, das mehr "woooow" ist :)

Lassen Sie uns eine Funktion erklären, die
nimmt 1. ein Zeiger auf Array von 5 Zeigern zu Funktionen, die jeweils float nehmen und doppelt zurückgeben.
2. Ein Zeiger auf ein Array von 3 Pontern zu Arrays von 4 Ints und gibt einen Zeiger auf Funktion zurück, die einen Zeiger zur Funktion nimmt int und einen Zeiger auf Funktion unter float und Rückgabe void und gibt unsigned int zurück.

Die typedef Lösung sein würde:

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); 

Nun, der lustige Teil :) Ohne typedefs wird dies:

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

Mein Gott, habe ich schreibe nur das? :)

+2

Wooooooooooooow – valdo

+0

@ Valdo: siehe meine Bearbeitung für eine schlechtere woooooow :) –

+0

Funny? Die nicht typisierte Version ist * perfekt * transparent. –

12

Die Spirale im Uhrzeigersinn Regel helfen: http://c-faq.com/decl/spiral.anderson.html

Es gibt drei einfache Schritte zu folgen:

mit dem unbekannten Element starten, in einer Spirale/Uhrzeigersinn bewegen; wenn ecountering folgende Elemente ersetzen sie mit den entsprechenden Erklärungen Englisch:

[X] oder [] => Array X Größe ... oder Array undefiniert Größe ...

(Typ1, Typ2) = > Funktion übergeben Typ1 und Typ2 Rückkehr ...

  • => Zeiger (n) ...

in einer Spirale/Uhrzeigersinn tun dies halten, bis alle Token abgedeckt wurden. Immer zuerst alles in Klammern auflösen!

Siehe „Beispiel # 3: Die‚Ultimate‘“, was so ziemlich genau das, was Sie fordern:

„-Signal ist eine Funktion einen int und einen Zeiger an eine Funktion einen int vorbei Rückkehr nichts (void) einen Zeiger auf eine Funktion der Rückkehr einen int vorbei nichts zurückkehrt (void)“

+0

Das ist so eine schöne Ressource. Vielen Dank ! – Shrayas

0

Installieren cdecl für Ihre Distribution (falls vorhanden) oder gehen here

Ansonsten glaube ich, Armen Tsirunyan Antwort richtig ist.

3

Falls Sie haben keinen Zugriff auf cdecl jetzt, hier ist die cdecl Ausgang:

$ 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