tipos tipo retorno propias otra matematicas llamar lista invocacion funciones funcion dentro definir dato c function prototype promotions

tipo - Promociones de argumento predeterminadas en llamadas a función C



tipo de dato retorno (3)

La respuesta de AProgrammer apoyada: esos son los bienes reales.

Para aquellos de ustedes que se preguntan por qué las cosas son así: en las oscuras edades anteriores a 1988, no existía el prototipo de función en el clásico "K & R" C, y las promociones de argumento predeterminadas se instituyeron porque (a) había esencialmente "libre", ya que no cuesta más poner un byte en un registro que poner una palabra en un registro, y (b) reducir los errores potenciales en el paso de parámetros. Esa segunda razón nunca lo cortó del todo, y fue por eso que la introducción de prototipos de funciones en ANSI C fue el cambio más importante que haya tenido lugar en el lenguaje C.

En cuanto a cuándo entran en vigencia las promociones predeterminadas : las promociones de argumento predeterminadas se usan exactamente cuando el tipo esperado del argumento es desconocido , es decir cuando no hay prototipo o cuando el argumento es varónico.

Preparar

Tengo algunas preguntas sobre las promociones predeterminadas de los argumentos cuando llamo a una función en C. Aquí está la sección 6.5.2.2 "Llamadas de función" Párrafos 6, 7 y 8 del estándar C99 (pdf) (énfasis agregado y dividido en listas para facilidad de leyendo):

Párrafo 6

  1. Si la expresión que denota la función llamada tiene un tipo que no incluye un prototipo , las promociones enteras se llevan a cabo en cada argumento, y los argumentos que tienen tipo float se promueven en el double . Estas se llaman promociones de argumento predeterminadas .
  2. Si el número de argumentos no es igual al número de parámetros, el comportamiento no está definido.
  3. Si la función se define con un tipo que incluye un prototipo , y el prototipo termina con puntos suspensivos ( , ... ) o los tipos de argumentos después de la promoción no son compatibles con los tipos de los parámetros, el comportamiento no está definido.
  4. Si la función se define con un tipo que no incluye un prototipo , y los tipos de argumentos después de la promoción no son compatibles con los de los parámetros posteriores a la promoción, el comportamiento no está definido, excepto en los siguientes casos:
    • un tipo promovido es un tipo entero con signo, el otro tipo promovido es el tipo entero sin signo correspondiente, y el valor es representable en ambos tipos;
    • ambos tipos son punteros a versiones calificadas o no calificadas de un tipo de carácter o void .

Párrafo 7

  1. Si la expresión que denota la función llamada tiene un tipo que incluye un prototipo , los argumentos se convierten implícitamente, como por asignación, a los tipos de los parámetros correspondientes, tomando el tipo de cada parámetro como la versión no calificada de su declaración. tipo.
  2. La notación de puntos suspensivos en un declarador de prototipo de función hace que la conversión del tipo de argumento se detenga después del último parámetro declarado. Las promociones de argumento predeterminadas se realizan en argumentos finales.

Párrafo 8

  1. Ninguna otra conversión se realiza implícitamente; en particular, el número y los tipos de argumentos no se comparan con los de los parámetros en una definición de función que no incluye un declarador de prototipo de función .

Lo que yo sé

  • Las promociones de argumento predeterminadas son char y short para int / unsigned int y float para double
  • Los argumentos opcionales para las funciones variadic (como printf ) están sujetos a las promociones predeterminadas del argumento

Para el registro, mi comprensión de un prototipo de función es esta:

void func(int a, char b, float c); // Function prototype void func(int a, char b, float c) { /* ... */ } // Function definition

Pregunta

Me está costando mucho trabajo descifrar todo esto. Aquí hay algunas preguntas que tengo:

  • ¿El comportamiento de las funciones de prototipo y no prototipado realmente difiere mucho, como con respecto a las promociones predeterminadas y las conversiones implícitas?
  • ¿Cuándo ocurren promociones de argumento predeterminadas? ¿Es siempre? ¿O es solo en casos especiales (como con funciones variadas)? ¿Depende de si una función es prototipo?

Su confusión se debe a un ligero malentendido de la terminología: tanto las declaraciones como las definiciones pueden incluir prototipos (o no):

void func(int a, char b, float c);

Esa es una declaración de función que incluye un prototipo.

void func(int a, char b, float c) { /* ... */ }

Esa es una definición de función que incluye un prototipo.

Los "prototipos" y "sin prototipos" son solo atributos de un tipo de función, y tanto las declaraciones como las definiciones introducen el tipo de función.

Entonces puedes tener una declaración sin un prototipo:

void func();

o puede tener una definición sin un prototipo (estilo K & R C):

void func(a, b, c) int a; char b; float c; { /* ... */ }


  • Los parámetros (no variados) de funciones con un prototipo se convierten al tipo correspondiente, que puede ser char, short, float.

  • Los parámetros de las funciones sin prototipo y parámetros variados están sujetos a promociones de argumento predeterminadas.

Si define una función con un prototipo y la utiliza sin el prototipo o viceversa y tiene parámetros de tipo char, corto o flotante, es probable que tenga un problema en el tiempo de ejecución. Tendrá el mismo tipo de problemas con las funciones variadas si el tipo promocionado no coincide con el utilizado al leer la lista de argumentos.

Ejemplo 1: problema al definir una función con un prototipo y usarla sin.

definition.c

void f(char c) { printf("%c", c); }

use.c

void f(); int main() { f(''x''); }

puede fallar porque se pasará un int y la función espera un char.

Ejemplo 2: problema al definir una función sin un prototipo y usarla con uno.

definition.c

void f(c) char c; { printf("%c", c); }

(Esta es una especie de definición muy anticuada)

use.c

void f(char c); int main() { f(''x''); }

puede fallar porque se espera una int, pero se pasará una char.

Nota: observará que todas las funciones de la biblioteca estándar tienen tipos que resultan de promociones predeterminadas. Entonces no causaron problemas durante la transición cuando se agregaron los prototipos.