Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

237
Vistas
Uso de punteros void (*)() para otras funciones

¿Es legal acceder a punteros a funciones con diferentes listas de argumentos a través de un puntero void (*f)() ? El siguiente programa se compila sin advertencias con gcc y parece funcionar correctamente, pero ¿es C legal?

 #include <stdio.h> #include <stdlib.h> typedef void funp(); static void funcall( funp* F, int args, double x) { switch( args) { case 0: F(); break; case 1: F(x); break; } } static void fun0( void) { printf( "zero\n"); } static void fun1( double x) { printf( "one\t%f\n", x); } int main( ) { funcall( (funp*)fun0, 0, 17.0); funcall( (funp*)fun1, 1, 17.0); return EXIT_SUCCESS; }

Compilé esto con

 gcc -Wpedantic -Wall -Wextra -std=gnu11 -O2 -o ./funp funp.c

Sería un comportamiento indefinido si el parámetro nargs no coincidiera con la cantidad de argumentos que tomó la función, pero ¿es legal si hay una coincidencia?

over 4 years ago · Santiago Trujillo
3 Respuestas
Responde la pregunta

0

En este caso particular, las llamadas son legales.

La sección 6.7.6.3p15 del estándar C explica qué hace que dos tipos de funciones sean compatibles (parte relevante en negrita):

Para que dos tipos de funciones sean compatibles, ambos deben especificar tipos de retorno compatibles. Además, las listas de tipos de parámetros, si ambos están presentes, deberán coincidir en el número de parámetros y en el uso del terminador de puntos suspensivos; los parámetros correspondientes tendrán tipos compatibles. Si un tipo tiene una lista de tipos de parámetros y el otro tipo está especificado por un declarador de función que no forma parte de una definición de función y que contiene una lista de identificadores vacía, la lista de parámetros no tendrá un terminador de puntos suspensivos y el tipo de cada parámetro será ser compatible con el tipo que resulte de la aplicación del argumento por defecto promociones. Si un tipo tiene una lista de tipos de parámetros y el otro tipo está especificado por una definición de función que contiene una lista de identificadores (posiblemente vacía), ambos deben coincidir en el número de parámetros y el tipo de cada parámetro prototipo debe ser compatible con el tipo. que resulta de la aplicación de las promociones de argumento por defecto al tipo del identificador correspondiente. (En la determinación de la compatibilidad de tipos y de un tipo compuesto, cada parámetro declarado con función o tipo de matriz se considera que tiene el tipo ajustado y cada parámetro declarado con tipo calificado se considera que tiene la versión no calificada de su tipo declarado).

Así que tienes un typedef con tipo:

 void()

Y funciones con tipo:

 void(void) void(double)

Las dos definiciones de función no usan puntos suspensivos ( ... ) por lo que satisface la primera condición. Para la segunda condición, veamos cuáles son las promociones de argumento predeterminadas . Se especifican en el apartado 6.5.2.2p6:

Si la expresión que denota la función llamada tiene un tipo que no incluye un prototipo, las promociones de enteros se realizan en cada argumento y los argumentos que tienen tipo float se promueven a double . Estos se denominan promociones de argumento predeterminado .

La primera función no tiene argumentos, por lo que es compatible. La segunda función tiene un solo argumento double , que coincide con las promociones de argumento predeterminadas, por lo que también es compatible.

Por poner algunos ejemplos más, las siguientes funciones también serían compatibles:

 void f1(long); void f2(int);

Pero estos no:

 void f3(float); void f4(char); void f5(short);
over 4 years ago · Santiago Trujillo Denunciar

0

Como señala otra respuesta, el código que mostró es C válido hoy . Pero eso puede cambiar en cualquier momento en el futuro, debido al uso de un tipo de función sin lista de parámetros.

6.11 Direcciones del idioma futuro

6.11.6 Declaradores de funciones

1 El uso de declaradores de función con paréntesis vacíos (no declaradores de tipo de parámetro en formato prototipo) es una característica obsoleta.

Una característica obsoleta es aquella que está sujeta a eliminación en futuras versiones estándar. Entonces, si desea que su código esté preparado para el futuro, es mejor evitarlo.

over 4 years ago · Santiago Trujillo Denunciar

0

Como se menciona en la respuesta de @StoryTeller, el uso de declaradores de funciones con paréntesis vacíos es una característica obsoleta, pero se puede evitar:

 #include <stdio.h> #include <stdlib.h> typedef void funp(void); static void funcall( funp* F, int args, double x) { switch( args) { case 0: F(); break; case 1: { typedef void fn(double); ((fn *)F)(x); } break; } } static void fun0( void) { printf( "zero\n"); } static void fun1( double x) { printf( "one\t%f\n", x); } int main( void ) { funcall( (funp*)fun0, 0, 17.0); funcall( (funp*)fun1, 1, 17.0); return EXIT_SUCCESS; }

EDITAR: se modificó la lista de parámetros de main para void el cumplimiento.


En respuesta a la consulta:

"Además, las listas de tipos de parámetros, si ambos están presentes, coincidirán en el número de parámetros" parecería significar que los tipos de funp y de fun1 son incompatibles. ¿Está bien lanzar?

La respuesta es sí, está bien lanzar. Del borrador C11 6.3.2.3 párrafo 8 :

Un puntero a una función de un tipo puede convertirse en un puntero a una función de otro tipo y viceversa; el resultado se comparará igual al puntero original. Si se utiliza un puntero convertido para llamar a una función cuyo tipo no es compatible con el tipo al que se hace referencia, el comportamiento no está definido.

En el código, el puntero a fun1 se convirtió en un tipo de puntero de función diferente en la llamada a funcall y se volvió a convertir al tipo original dentro de funcall para que pueda usarse para llamar a fun1 .

over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda