¿Por qué printf () promueve un flotador a un doble?

De una pregunta anterior:

Si intentas pasar un float a printf , se promoverá que se double antes de que printf reciba

printf() es una función variadica ¿no? Entonces, ¿una función variadica promueve un argumento float a un double antes de pasarlo?

Sí, los argumentos de flotación a la función variadica se promueven como dobles.

El borrador de la sección estándar de C99 6.5.2.2 Llamadas de función dice:

[…] y los argumentos que tienen tipo float son promovidos al doble. Estos se llaman las promociones de argumento por defecto. […]

del borrador de la sección estándar de C ++ 5.2.2 Llamada de función:

[…] un tipo de punto flotante que está sujeto a la promoción de coma flotante (4.6), el valor del argumento se convierte al tipo promocionado antes de la llamada. […]

y la sección 4.6 :

Un prvalue de tipo float se puede convertir a un prvalue de tipo double. El valor no ha cambiado

cppreference cubre las conversiones predeterminadas para la función variadica en C ++ y así:

  • std :: nullptr_t se convierte a void *
  • los argumentos flotantes se convierten al doble como en la promoción de coma flotante
  • Las enumeraciones de bool, char, short y unscoped se convierten en tipos enteros int o más amplios como en la promoción entera

Podemos ver en C y, presumiblemente, en C ++, esta conversión se mantuvo para la compatibilidad con K & R C , de Rationale for International Standard-Programming Languages-C ( énfasis mío ):

Por compatibilidad con la práctica anterior, todas las promociones de argumentos ocurren como se describe en K & R en ausencia de una statement de prototipo, incluida la promoción no siempre deseable de float a double .

En cuanto a la parte del por qué de la pregunta, es simple: los estándares C (y C ++) consideran que el double es el tipo de coma flotante “predeterminado”. No float (que es lo que muchos de los progtwigdores usamos por defecto cuando usamos números de coma flotante).

Esto se puede ver al observar:

  1. 3.14 es un double (si quieres un float , debes dar un paso adicional y anexar un f )
  2. Las funciones matemáticas estándar tienen un double por defecto (por ejemplo, sin() toma un double , si quieres un float tienes que usar sinf() )

Con esto, parece más “natural” que un float sea ​​promovido al double en una llamada de función variadica, dado que el double es el predeterminado “natural” en el lenguaje.

Dado un prototipo de función, tipo float solo se promociona automáticamente 1 cuando se usa en argumentos finales. La función de impresión los usa:

 int printf(const char * restrict format, ...); 

1 (Citado de: ISO / IEC 9899: llamadas de función de 201x 6.5.2.2)
6. las promociones enteras se realizan en cada argumento, y los argumentos que tienen tipo float se promueven en el doble. Estas se llaman promociones de argumento predeterminadas.
7. Las promociones de argumento predeterminadas se realizan en argumentos finales.

Porque el estándar (C99 o C11 ) lo dice. Ver respuesta por 2501 .

Hay varias razones pragmáticas para eso: historia (las primeras implementaciones de C se han usado para la progtwigción del sistema, donde las operaciones de coma flotante no importan), y el hecho de que en los procesadores actuales (tableta, computadora de escritorio, servidor …), aritmética las operaciones en double son casi tan eficientes como float (pero algunos microcontroladores baratos no tienen ninguna FPU, o solo pueden agregar float por hardware, y requieren una biblioteca para cada operación en double ). Por último, supongo que tal regla permite convenciones de llamadas ligeramente más simples y ABI s.

Piense en float como una especie de short double (que, por supuesto, es ilegal en C). Un float es útil principalmente cuando necesita compactar memoria (y puede permitirse la pérdida de precisión). Ver también http://floating-point-gui.de/ para más.