¿Se puede llamar a una función C con argumentos adicionales?

Considere el siguiente código:

#include  typedef int (*addif_fn_t) (int, int, int); int add (int a, int b) { return a + b; } int addif (int a, int b, int cond) { return cond ? (a + b) : 0; } int main() { addif_fn_t fn; fn = addif; printf("addif:\t%d %d\n", fn(1, 2, 1), fn(1, 2, 0)); fn = (addif_fn_t)add; printf("add:\t%d %d\n", fn(1, 2, 1), fn(1, 2, 0)); return 0; } 

En cualquier máquina Intel que use la convención estándar de llamadas C, esto se traduce en:

 addif: 3 0 add: 3 3 

La pregunta es: ¿qué tan portátil es este modismo? ¿C permite llamar a una función con más parámetros de los que acepta?

Supongo que depende completamente de la ABI y de cómo determina dónde se almacenan los argumentos de la función y las variables locales. Más al punto, es probable que este no sea un código portátil. Pero he visto este lenguaje usado varias veces en bases de código reales.

En la práctica, no sé qué tan “portátil” es (en el sentido de si se comportará como esperaba en las implementaciones existentes, o al menos en el subconjunto de implementaciones que le preocupan).

En lo que respecta al estándar C, no es portátil en absoluto. Su progtwig tiene un comportamiento indefinido, porque llama a una función a través de una expresión de un tipo ( int(*)(int, int) que difiere del tipo real de la función ( int(*)(int, int, int) ). (El primero es el tipo usado para definir la función de add ; el segundo es el tipo de la expresión fn usada como el prefijo de la llamada).

Esto se establece en la norma C , sección 6.5.2.2, párrafo 9:

Si la función se define con un tipo que no es compatible con el tipo (de la expresión) señalado por la expresión que denota la función llamada, el comportamiento no está definido.

(El enlace es a un PDF del borrador N1570 del estándar C11. Encontrará una redacción similar, o probablemente idéntica, en otras ediciones del estándar).

Mi consejo: No hagas eso.

Sin embargo, tenga en cuenta que los argumentos en exceso para funciones variadic (funciones como printf() que se declaran con un , ... ) se ignoran silenciosamente. Por ejemplo, esto es perfectamente legal:

 printf("Ignore the arguments\n", 10, 20, 30); 

Si realmente necesita poder llamar a una función sin saber cuántos argumentos espera, este podría ser un enfoque viable (aunque perderá la verificación de tipo de comstackción para cualquier argumento que coincida con el , ... ).

Para las funciones no variadas, puede convertir libremente los punteros de función de un tipo a otro, pero debe volver a convertir el tipo correcto para cada llamada.