¿Cuál es la diferencia entre% f y% lf en C?

Vi estos dos parámetros en un ejemplo de C en un libro de C, pero el autor no explicó cuál es la diferencia entre los dos. Sé que %f especifica que un flotador debe ocupar su lugar. Intenté buscar esto, pero me costó mucho encontrar estos símbolos. ¿Qué hay de %lf ?

No hay diferencia en la familia printf . La norma ISO C11 (todas las referencias a continuación son de C11), sección 7.21.6.1 The fprintf function , párrafo /7 estados, para el modificador l (mi negrita):

Especifica que un siguiente especificador de conversión d, i, o, u, x, o X se aplica a un argumento int largo o sin signo largo int; que un siguiente especificador de conversión se aplica a un puntero a un argumento int largo; que un especificador de conversión c siguiente se aplica a un argumento wint_t; que el siguiente especificador de conversión s se aplica a un puntero a un argumento wchar_t; o no tiene efecto en los siguientes especificadores de conversión a, A, e, E, f, F, g o G.

La razón por la que no necesita modificar el especificador f es porque ese especificador ya denota un double , del párrafo /8 de esa misma sección:

Un argumento doble que representa un número de punto flotante se convierte a notación decimal en el estilo …

Esto tiene que ver con el hecho de que los argumentos que siguen a la elipse en el prototipo de función están sujetos a promociones de argumentos predeterminados según la sección 6.5.2.2 Function calls , párrafo /7 :

… La notación de puntos suspensivos en un declarador de prototipo de función hace que la conversión de tipo de argumento se detenga después del último parámetro declarado. Las promociones de argumentos predeterminados se realizan en los argumentos finales.

Dado que printf (de hecho, toda la familia de funciones parecidas a printf ) se declara como int printf(const char * restrict format, ...); con la notación de puntos suspensivos, esa regla se aplica aquí. Las promociones de argumentos predeterminadas se tratan en la sección 6.5.2.2 Function calls , párrafo /6 :

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 el tipo float se promueven al doble. Estos se llaman las promociones de argumento por defecto.


Para la familia scanf , exige el uso de un double lugar de un float . Sección 7.21.6.2 The fscanf function /11 :

Especifica que el siguiente especificador de conversión d, i, o, u, x, X o n se aplica a un argumento con puntero de tipo a largo int o unsigned long int; que el siguiente especificador de conversión a, A, e, E, f, F, g o G se aplica a un argumento con puntero de tipo para duplicar; o que el siguiente especificador de conversión c, s, o [se aplica a un argumento con puntero de tipo a wchar_t.

Esto modifica el párrafo /12 de esa sección que indica, para %f :

Coincide con un número de punto flotante, infinito o NaN, opcionalmente firmado, cuyo formato es el mismo que el esperado para la secuencia del sujeto de la función strtod. El argumento correspondiente será un puntero a flotante.

Para scanf , %f lee en un float , y %lf lee en un double .

Para printf : en C99 y versiones posteriores, ambos son idénticos e imprimen un float o un double . En C89, %lf causó un comportamiento indefinido aunque era una extensión común para tratarlo como %f .

La razón por la que se puede usar un especificador para dos tipos diferentes en printf es debido a las promociones de argumentos predeterminados ; los argumentos de tipo float se promueven para double cuando se usan para llamar a una función y no coinciden con un parámetro en un prototipo de función. Así que printf solo ve un double en cualquier caso.

El modificador de ancho en% lf es ignorado graciosamente por printf (). O, para ser más precisos,% f toma un doble – varargs siempre promoverá que los argumentos flotantes se dupliquen.