2010-03-11 16 views
9

me escribió este pequeño código:printf de una variable size_t con identificadores de tipo de LLD, LD y d

#include <stdio.h> 
int main() { 
    size_t temp; 
    temp = 100; 

    printf("lld=%lld, ld=%ld, u=%u\n", temp, temp, temp); 

    return 0; 
} 

Estoy funcionando esto en una máquina i386 GNU/Linuxcon versión de gcc 4.1.1 20070105 (Red Hat 4.1.1-52). Esta es la salida que me dieron:

lld=429496729700, ld=100, u=7993461 

Puedo entender que la primera (lld) se imprimió como basura porque los printf intentos para imprimir 8 bytes (para signed long long como indica lld) cuando sólo 4 bytes están disponibles de la variable temp. Pero no entiendo por qué el último identificador, u se está imprimiendo como basura, mientras que, en mi entender, este es el identificador aplicable más cercano para size_t.

Aquí he supuesto que size_t es unsigned int (que tiene 4 bytes firmados para mi i386).

Ahora, lo hice un poco de ajuste con la línea printf:

... 
printf("ld=%ld, u=%u, lld=%lld\n", temp, temp, temp); 
... 

y tengo una respuesta perfectamente bien (excepto la parte lld).

ld=100, u=100, lld=34331653576851556 

¿Puede alguien ayudarme a comprender qué es exactamente lo que me falta aquí?

¡Muchas gracias por cualquier ayuda!

[nota al margen: He intentado cambiar la optimización del uso de gcc -O[0,2] etiqueta de encendido/apagado sin ninguna diferencia en la observación.]

+0

La opción -What probablemente detectará esta incompatibilidad por usted. – Clifford

+0

@Clifford Gracias por la entrada, pero estaba usando deliberadamente especificadores incorrectos. De hecho, quería saber cómo 'printf' estaba consumiendo los elementos en la pila. De hecho, creo que Wall también tendría lo mismo. Sin embargo, muchas gracias. – Shrey

+0

Me doy cuenta de que fue deliberado; pero mi punto era que si la intención era observar el comportamiento del compilador, la opción -Wformat demuestra un comportamiento alternativo (y más seguro), que puede haber sido de interés para alguien, incluso si ya lo sabía. -Wall no incluyó -What en versiones anteriores de GCC. – Clifford

Respuesta

22

Esto se debe a lo que ha empujado en la pila es de tres valores de 32 bits y su cadena de formato intenta usar cuatro de ellos o, más exactamente, un valor de 64 bits y dos valores de 32 bits.

En el primer caso, el lld absorbe dos valores de 32 bits, el ld chupa hasta la tercera y la u consigue cualquier cosa que esté en la pila después de eso, lo que realmente podría ser cualquier cosa.

Cuando se cambia el orden de los especificadores de formato en la cadena, que funciona de manera diferente debido a que el ld succiona el primer valor de 32 bits, el u absorbe el segundo y el lld absorbe la tercera más pase lo que pase estar en la pila después de eso. Es por eso que obtienes diferentes valores, es un problema de alineación/disponibilidad de datos.

Puede ver esto en acción con el primer valor. 429496729700 es igual a (4294967296 + 1) * 100, es decir, (2 +1) * 100.Su fragmento de código

printf("lld=%lld, ld=%ld, u=%u\n", temp, temp, temp); 

en realidad tiene el siguiente efecto:

What you pass  Stack  What printf() uses 
-------------  -----  ------------------ 
       +-----+ 
100    | 100 | \ 
       +-----+ = 64-bit value for %lld. 
100    | 100 |/
       +-----+ 
100    | 100 | 32-bit value for %ld. 
       +-----+ 
       | ? | 32-bit value for %u (could be anything). 
       +-----+ 

En el segundo caso

printf("ld=%ld, u=%u, lld=%lld\n", temp, temp, temp); 

ocurre lo siguiente:

What you pass  Stack  What printf() uses 
-------------  -----  ------------------ 
       +-----+ 
100    | 100 | 32-bit value for %ld. 
       +-----+ 
100    | 100 | 32-bit value for %u. 
       +-----+ 
100    | 100 | \ 
       +-----+ = 64-bit value for %lld (could be anything). 
       | ? |/
       +-----+ 
+0

Sí, esto suena a la perfección la respuesta que estaba buscando. Leí el código de ensamblaje y también lo que mencionaste (la parte de empujar 3 variables de 32 bytes en la pila). Simplemente no podía confirmar cómo printf los estaba consumiendo. ¡Gracias por confirmar! – Shrey

0

Usted está de paso a printf el número equivocado de b ytes. % lld requiere un número entero más grande, en su caso la manera en que% ld tomó su argumento está completamente desordenado, ya que esperaría un valor de 64 bits.

7

Su código muestra adecuadamente el Comportamiento no definido. Tenga en cuenta que, en el caso de los argumentos variados, no se realiza ninguna verificación de tipo para los parámetros. Aquí es cuando se necesita un lanzamiento explícito. De hecho, el siguiente, por lo tanto se debe utilizar:

printf("lld=%lld, ld=%ld, u=%u\n", 
     (unsigned long long)temp, 
     (unsigned long)temp, 
     (unsigned int)temp); 

Como acotación al margen recuerda el especificador de size_t es z. Entonces:

printf("zd=%zd\n", temp); 
Cuestiones relacionadas