¿Qué significan los paréntesis alrededor del nombre de una función?

214

En uno de mis archivos fuente del proyecto, encontré esta definición de función C:

int (foo) (int *bar)
{
    return foo (bar);
}

Nota: no hay un asterisco al lado foo, por lo que no es un puntero de función. ¿O es eso? ¿Qué está pasando aquí con la llamada recursiva?

usuario1859094
fuente
77
No, no es un puntero de función, sigue siendo una función normal llamada foo.
Nemanja Boric
¿Es esta la función completa?
asheeshr
2
¿Tiene evidencia de que esta función se utiliza en un contexto útil?
moooeeeep
1
... parece una función ficticia que tal vez solo se escribió para ver si se compila, en la fuente existente, y debería haberse eliminado. Lo eliminaría (si eso es lo que realmente hace la función), ya que en el mejor de los casos será un bucle infinito (no estoy seguro de si el compilador de C puede optimizar esa llamada de cola para saltar), en el peor desbordamiento de la pila.
hyde
3
Los paréntesis en las declaraciones en C ayudan a confundir el lenguaje ambiguo. ¿Qué es rápido a(b);? Declaración de bcomo una variable de tipo a? ¿O una llamada a funcionar acon argumento b? La diferencia es sintáctica, y no puede saber de qué manera analizarla sin buscar la información de declaración de a; es decir, esos paréntesis de llamada de función postfix, o paréntesis opcionales alrededor de un declarador.
Kaz

Respuestas:

329

En ausencia de cosas de preprocesador, foola firma es equivalente a

int foo (int *bar)

El único contexto en el que he visto a personas poner paréntesis aparentemente innecesarios alrededor de los nombres de funciones es cuando hay una función y una macro similar al mismo nombre, y el programador quiere evitar la expansión de la macro.

Esta práctica puede parecer un poco extraña al principio, pero la biblioteca C establece un precedente al proporcionar algunas macros y funciones con nombres idénticos .

Una de estas funciones / macro par es isdigit(). La biblioteca podría definirlo de la siguiente manera:

/* the macro */
#define isdigit(c) ...

/* the function */
int (isdigit)(int c) /* avoid the macro through the use of parentheses */
{
  return isdigit(c); /* use the macro */
}

Su función se ve casi idéntica a la anterior, por lo que sospecho que esto también está sucediendo en su código.

NPE
fuente
2
Ese puede ser el caso aquí también; No busqué macros ... Y no sabía que la expansión de macro no tiene lugar entre paréntesis, ¡Gracias por señalarlo!
user1859094
13
@ user1859094: En una segunda mirada, esto es casi seguro lo que está sucediendo en su código. El foo(bar)interior de la función está utilizando la macro correspondiente.
NPE
78
@ user1859094 la expansión de macros se lleva a cabo entre paréntesis, pero la expansión de una macro similar a una función solo se lleva a cabo si el siguiente token es un paréntesis izquierdo (C99, 6.10.3§10), por foo (int* bar)lo que sería reemplazado, pero no (foo) (int *bar)(el siguiente token después fooes ))
Virgile
44
¿Cómo se llamaría tal función? ¿Lo llamarías también entre paréntesis? Por ejemplo, ¿funcionaría esto (isdigit)(5)?
gcochard
44
@ Greg: Correcto, así es exactamente como lo llamarías.
NPE
37

Las paréntesis no cambian la declaración, todavía solo define una función ordinaria llamada foo.

La razón por la que se han utilizado es casi con certeza porque hay una macro similar a una función llamada foodefinida:

#define foo(x) ...

El uso (foo)en la declaración de función evita que esta macro se expanda aquí. Entonces, lo que probablemente está sucediendo es que una función foo()se está definiendo con su cuerpo expandido desde la macro similar a una función foo.

coste y flete
fuente
55
Buena deducción (aunque el uso de paréntesis para este propósito debe ser punible por ley).
Ugoren
3
@ugoren: usar parens alrededor del nombre de la función es la única forma de evitar una expansión de macro para una macro similar a una función. A veces es una herramienta necesaria.
Michael Burr
77
@MichaelBurr, también existe la opción de no tener una macro y funcionar con el mismo nombre. Sé que no siempre puedes controlar todo, pero si llegaste a esta solución, diría que algo está muy mal.
Ugoren
-3

Los paréntesis no tienen sentido.
El código que muestra no es más que una recursión infinita.

Al definir un puntero de función, a veces ve paréntesis extraños que significan algo. Pero este no es el caso aquí.

Ugoren
fuente
66
Evidentemente no; los paréntesis evitan la expansión macro. Ver la respuesta aceptada.
Kevin
12
@Kevin, mi respuesta es sobre el código que se muestra y es correcto. En casi cualquier pregunta C aquí, asumir que las definiciones de preprocesador desconocidas pueden cambiar todo. En este caso, las respuestas que consideran el preprocesador son realmente mejores, pero no hace que la mía sea incorrecta.
ugoren