2008-10-16 21 views
162

Por qué es que scanf() necesita la l en "%lf" cuando se lee un double, cuando printf() puede utilizar "%f" independientemente de si su argumento es un double o una float?¿Por qué scanf() necesita "% lf" para dobles, cuando printf() está bien con solo "% f"?

código Ejemplo:

double d; 
scanf("%lf", &d); 
printf("%f", d); 
+1

No entiendo lo que quiere decir con POINTER aquí. En scanf solo pasamos la dirección variable (ie) entonces dónde está el puntero –

+7

@deetchanya En C, cuando "toma la dirección de" una variable con el operador unario '&', el resultado de esa operación es un puntero al ubicación de almacenamiento de la variable en la memoria. Es ese puntero que se pasa a 'scanf'. – zwol

+0

esta es una publicación más sobre este https: // stackoverflow.com/questions/9291348/why-is-scanf-not-working-as-expected-when-writing-to-a-string-literal – vimalpt

Respuesta

192

Debido C promoverá flotadores a dobles para las funciones que toman argumentos variables. Los punteros no se promocionan a nada, por lo que debe usar %lf, %lg o %le (o %la en C99) para leer en dobles.

+3

Las promociones predeterminadas de argumento son C estándar, no solo MSVC. –

+0

Reparado según su comentario. ¡HURRA! – MSN

+4

+1 por ser exactamente correcto. En mi humilde opinión, muestra que scanf() es una función horrible que solo deberías tolerar si no hay otra alternativa. Es demasiado fácil introducir defectos insidiosos al pasar punteros al tipo incorrecto de datos y, por supuesto, no hay ningún tipo de comprobación de los parámetros que le pasa. – AAT

16

scanf necesita conocer el tamaño de los datos que están siendo apuntado por &d para llenar correctamente, mientras que las funciones variadic promueven flotadores a los dobles (no del todo seguro de por qué), por lo printf está consiguiendo siempre un double.

+1

Una función variadica es muy frágil, porque necesita saber el tipo y el tamaño exacto de todas las parámetros pasados ​​a él, y no puede hacer cumplir esto en tiempo de compilación. Si una variable es del tipo incorrecto, el wron g valor será leído; si tiene el tamaño incorrecto, todas las variables posteriores también se leerán mal. Si se pudieran pasar dos tamaños diferentes de flotador, entonces causaría todo tipo de problemas desagradables y fáciles de perder. – mwfearnley

2

El uso de un flotador o un valor doble en una expresión C dará como resultado un valor que es doble de todos modos, por lo que printf no puede notar la diferencia. Mientras que un puntero a un doble tiene que ser señalado explícitamente para scanf como distinto de un puntero para flotar, porque lo que el puntero apunta es lo que importa.

+5

float se convierte a double * en este caso * porque los argumentos son parte de una lista de argumentos de longitud variable, los flotantes no siempre se convierten a dobles en C. –

+1

En versiones pre-estándar del lenguaje C los valores 'float' se activaron automáticamente promovido a 'doble' en expresiones. Esa regla fue abandonada en el estándar C. Generalmente, 'float' no es promovido a' double' en las expresiones. Solo se promociona a "doble" cuando se pasa como argumento variado, que es lo que sucede en este caso. – AnT

7

Porque de lo contrario, scanf pensará que está pasando un puntero a un flotador que es un tamaño más pequeño que un doble, y devolverá un valor incorrecto.

20

Desde 1999, la coincidencia entre los especificadores de formato y los tipos de argumento de coma flotante en C es consistente entre printf y scanf. Es

  • %f para float
  • %lf para double
  • %Lf para long double

Lo que pasa es que cuando argumentos de tipo float se pasan como parámetros variadic, tales argumentos se convierten implícitamente escribir double. Esta es la razón por la cual en printf, los especificadores de formato %f y %lf son equivalentes e intercambiables. En printf puede "usar de forma cruzada" %lf con float o %f con double.

Pero no hay razón para hacerlo en la práctica. No use %f a printf argumentos del tipo double. Es un hábito generalizado que nació en C89/90 veces, pero es un mal hábito. Utilice %lf en printf para double y mantenga %f reservado para float argumentos.

+0

Diría que usar '% f' en printf es un buen hábito porque entonces su código siempre funciona, mientras que usar'% lf' puede fallar si el compilador no tiene una biblioteca compatible con C99. Lamentablemente, esa situación sucede en la realidad. –

Cuestiones relacionadas