Pregunta

Configuración

Tengo algunas preguntas sobre las promociones de argumentos predeterminadas al llamar a una función en C.Aquí está la sección 6.5.2.2 "Llamadas a funciones" Párrafos 6, 7 y 8 de la Estándar C99 (pdf) (énfasis añadido y dividido en listas para facilitar la lectura):

Párrafo 6

  1. 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 son promovidos a double.Estos se llaman los promociones de argumentos predeterminados.
  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 está definida 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 parámetros, el comportamiento no está definido.
  4. Si la función está definida 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 después de la promoción, el comportamiento es indefinido, excepto en los siguientes casos:
    • un tipo promocionado es un tipo entero con signo, el otro tipo promocionado es el tipo entero sin signo correspondiente y el valor se puede representar 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 tipo declarado.
  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 argumentos predeterminadas se realizan en argumentos finales.

Párrafo 8

  1. No se realizan otras conversiones 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é

  • El promociones de argumentos predeterminados son char y short a int/unsigned int y float a double
  • Los argumentos opcionales para funciones variadas (como printf) están sujetos al argumento predeterminado promociones

Para que conste, mi comprensión de un prototipo de función Es esto:

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 asimilar todo esto.Aquí hay algunas preguntas que tengo:

  • ¿El comportamiento de las funciones prototipadas y no prototipadas realmente difiere tanto, como en lo que respecta a las promociones predeterminadas y las conversiones implícitas?
  • ¿Cuándo ocurren las promociones de argumentos predeterminados?¿Es siempre?¿O es solo en casos especiales (como con funciones variadas)?¿Depende de si se crea un prototipo de una función?
¿Fue útil?

Solución

-respuesta a los

de upvoted AProgrammer son los bienes reales.

Para aquellos de ustedes que se preguntan ¿Por qué las cosas son de esta manera: en la Edad Media antes de 1988, no había tal cosa como un prototipo de función en el clásico "K & R" C, y el argumento por defecto promociones se iniciaron debido a que (a) no eran esencialmente "libre", ya que no cuesta más que poner un byte en un registro que poner una palabra en un registro, y (b) de reducir los posibles errores en la transmisión de parámetros. Esa segunda razón nunca lo cortó, y por eso la introducción de prototipos de funciones en ANSI C fue el único cambio más importante que se haya en el lenguaje C.

En cuanto a cuando un tiro promociones por defecto en: promociones argumento por defecto se utilizan exactamente cuando el tipo esperado del argumento es desconocida , que es decir cuando no hay prototipo o cuando el argumento es variadic.

Otros consejos

  • (Non variadic) parámetros a funciones con un prototipo se convierten al tipo correspondiente, que puede ser char, short, flotador.

  • Los parámetros a funciones sin parámetros prototipo y variadic están sujetos a los valores predeterminados promociones argumento.

Si se define una función con un prototipo y utilizarlo sin el prototipo o viceversa y tiene parámetros de tipo char, corta o flotador, es probable que tenga un problema en tiempo de ejecución. Vas a tener el mismo tipo de problemas con las funciones variadic si el tipo promovido no coincide con lo que se utiliza cuando se lee la lista de argumentos.

Ejemplo 1:. Problema en la definición de una función con un prototipo y utilizarlo sin

definition.c

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

use.c

void f();

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

puede fallar porque se pasa un entero y la función espera un char.

Ejemplo 2:. Problema cuando se define una función sin un prototipo y su uso con un solo

definition.c

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

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

use.c

void f(char c);

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

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

Nota: podrás notar que todas las funciones de la biblioteca estándar tienen tipos que resultan de las promociones por defecto. Así que ellos no causaron problemas durante la transición cuando se añadieron los prototipos.

Su confusión proviene de una muy ligera falta de comprensión de la terminología - ambas declaraciones y definiciones pueden incluir prototipos (o no):

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

Esto es una función declaración que incluye un prototipo.

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

Esto es una función Definición que incluye un prototipo.

"de prototipos" y "no-prototipo" son sólo los atributos de una función type , y ambas declaraciones y definiciones introducen el tipo de la función.

Así que usted puede tener una declaración y no un prototipo:

void func();

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

void func(a, b, c)
    int a;
    char b;
    float c;
{ /* ... */ }
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top