2010-11-08 30 views
12

Hoy en día, estaba leyendo el APUE.and me encontré con la función definida de la siguiente manera:¿Cómo entender esta definición

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

que estaba confundido, sé señal es puntero a una función y el último (int) es su parámetro no sabía lo que es (int signo, void (* func) (int)).

señal
+1

Get 'cdecl'. Te dirá todas estas cosas. Pregunto: 'explicar void (* signal (int, void (*) (int))) (int);' y responde: 'declare signal como function (int, puntero a function (int) return void) devolviendo el puntero a function (int) return void' –

+0

intente http://cdecl.org/ –

Respuesta

23

El procedimiento general : encuentre el identificador de la izquierda y hágalo salir. En ausencia de una agrupación explícita con paréntesis, los operadores de postfix como () y [] se unen antes de los operadores unarios como *; Por lo tanto, los siguientes son todas verdaderas:

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 

aplicación de estas reglas a la declaración, se descompone como

 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 resumen signal, devuelve un puntero a una función que devuelve void. signal toma dos parámetros: un entero y un puntero a otra función que devuelve void.

Puede usar typedefs para que esto sea más fácil de leer (y la página del manual para signal en Ubuntu Linux hace precisamente eso); sin embargo, creo que es valioso mostrar la versión no tipificada para demostrar exactamente cómo funciona la sintaxis. La instalación typedef es maravillosa, pero realmente necesita comprender cómo funcionan los tipos subyacentes para usarla de manera efectiva.

La función signal configura un manejador de señal; el segundo argumento es la función que se debe ejecutar si se recibe una señal. Se devuelve un puntero al controlador de señal actual (si existe).

Por ejemplo, si desea que su programa para manejar señales de interrupción (por ejemplo, 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; 
} 

EDITAR extendí el código de ejemplo para signal a algo que es de esperar más ilustrativo.

+1

+1 para una respuesta maravillosa! – Shrayas

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

es función que toma int y un puntero a funcionar toma int y regresar vacío y devuelve un puntero a función toma int y regresar vacío. Es decir,

typedef void(*funcPtr)(int) 

entonces tenemos

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

La sintaxis es realmente extraño, y tales cosas mejor hacerse con un typedef. A modo de ejemplo, si desea declarar una función que toma un entero y devuelve un puntero a una función de tomar carbón y volviendo doble será

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

Editar: después de un comentario que dice "Ostras", me estoy proporcionando otro ejemplo que es más "woooow" :)

Vamos a declarar una función que toma
1. un puntero al arreglo de 5 punteros a funciones de cada uno tomando flotador y regresar doble.
2. un puntero a una matriz de 3 ponters para matrices de 4 entradas
y devuelve un puntero a la función que toma un puntero para funcionar tomando int y devolviendo un puntero a la función tomando flotante y devolviendo vacío y devuelve unsigned int.

La solución typedef sería la siguiente:

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

Ahora, la parte divertida :) Sin typedefs esto será:

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

Mi dios, qué acabo de escribir eso? :)

+2

Wooooooooooooow – valdo

+0

@valdo: vea mi edición para un wooooow peor :) –

+0

¿Divertido? La versión sin tipo es * perfectamente * transparente. –

12

La regla espiral a la derecha le ayudará: http://c-faq.com/decl/spiral.anderson.html

Hay tres pasos simples a seguir:

empezando por el elemento desconocido, se mueven en una dirección en espiral/las agujas del reloj; cuando ecountering los siguientes elementos reemplazarlos con los estados correspondientes en inglés:

tamaño

[X] o [] => Array X ... o de matriz de tamaño indefinido de ...

(tipo 1, tipo 2) = > función de paso tipo 1 y tipo 2 volver ...

  • => puntero (s) a ...

seguir haciendo esto en un/espiral hacia la derecha hasta que todas las fichas han sido cubiertos. ¡Siempre resuelve cualquier cosa entre paréntesis primero!

Véase "Ejemplo # 3: El 'Ultimate'", que es casi exactamente lo que está pidiendo:

"señal es una función que pasa un entero y un puntero a una función que pasa un int nada (void) que devuelve un puntero a una función que pasa un int nada de vuelta (void) volver"

+0

Este es un recurso tan hermoso. Gracias ! – Shrayas

0

Instalar cdecl para su distribución (si está disponible) o visite here

de lo contrario, creo que la respuesta de Armen Tsirunyan es correcta.

3

En caso de que no tiene acceso a cdecl en este momento, aquí está la salida 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 
Cuestiones relacionadas