2011-09-20 13 views
14

Estoy tratando de aprender C leyendo C Programming Language, 2nd Edition. Tengo alguna experiencia en programación, pero no con C.¿Qué le sucede a una variable flotante cuando% d se usa en una impresión?

estoy actualmente en el Capítulo 1. Tengo el siguiente código:


float f; 
    for (f = 0.0; f <= 3; f += 1.1) 
     printf("A: %3f B: %6.2f\n", f, f + 0.15); 

Se imprime la salida:

A: 0.000000 B: 0.15 
A: 1.100000 B: 1.25 
A: 2.200000 B: 2.35 

Se ve bien.


Ahora puedo cambiar el printf de la siguiente manera:

printf("A: %3d B: %6.2f\n", f, f + 0.15); 

la nueva salida es

A: 0 B: 0.00 
A: -1610612736 B: 0.00 
A: -1610612736 B: -625777476808257557292155887552002761191109083510753486844893290688350183831589633800863219712.00 

lo que está pasando aquí? Esperaría que el flotador se convirtiera en int porque usé% d pero eso no fue lo que sucedió. Además, ¿por qué el valor B también salió mal? ¿Qué pasó con f aquí?

+2

No le pediste que lo convirtiera a un int, le dijiste que ** era ** un int! Basura dentro basura fuera. –

Respuesta

15

Cuando llamó:

printf("A: %3d B: %6.2f\n", f, f + 0.15); 

C convierte automáticamente los float valores a double (es una conversión estándar realizada cuando llama a una función que toma argumentos variables, como int printf(const char *fmt, ...);). En aras de la argumentación, asumiremos que sizeof(int) es 4 y sizeof(double) es 8 (hay excepciones, pero son pocas y distantes).

La llamada, por lo tanto, ha insertado un puntero en la pila, más un doble de 8 bytes para f y otro doble de 8 bytes para f + 0.15. Cuando está procesando la cadena de formato, %d dice printf() que presionó un int de 4 bytes en la pila después de la cadena de formato. Como eso no es lo que hiciste, has invocado un comportamiento indefinido; lo que suceda después está bien según el estándar C.

Sin embargo, la implementación más probable lee alegremente 4 bytes y los imprime como si fueran int (confía en que diga la verdad). Luego aparece el formato %6.2f; leerá 8 bytes de la pila como double. Existe la posibilidad de que esto provoque un error de memoria en el acceso desalineado (se necesitaría una máquina de 64 bits con el requisito de que double esté alineado en un límite de 8 bytes, como un SPARC), o leerá 4 bytes de f y 4 bytes desde f + 0.15, juntándolos para crear un valor double bastante inesperado, como muestra su ejemplo.

+0

gran respuesta, por lo que puede 'printf (" A:% d% d B:% 6.2 ", ...' y obtener valores incorrectos pero B no se verá afectado –

+1

Bajo una gran cantidad de suposiciones bastante plausibles, sí . El comportamiento es estrictamente indefinido, pero en la práctica, sí. –

8

Printf tratará la memoria que señale como usted lo indique. No hay conversión pasando. Está tratando la memoria que representa el flotador como un int. Debido a que los dos se almacenan de manera diferente, obtienes lo que es esencialmente un número aleatorio.

Si desea dar salida a su flota como un entero, se echa primero:

printf("A: %3d B: %6.2f\n", (int)f, f + 0.15); 
+1

Bien, eso tiene sentido. Entonces, ¿cambió el valor de f porque no lo fundí como int? Si no es así, entonces la segunda parte del printf está usando% 6.2f así que ¿debería al menos tener el valor correcto? – Gollum

Cuestiones relacionadas