printf de una variable size_t con identificadores de tipo lld, ld y d

Escribí este pequeño código:

#include  int main() { size_t temp; temp = 100; printf("lld=%lld, ld=%ld, u=%u\n", temp, temp, temp); return 0; } 

Estoy ejecutando esto en una máquina i386 GNU / Linux con gcc versión 4.1.1 20070105 (Red Hat 4.1.1-52) . Este es el resultado que obtuve:

 lld=429496729700, ld=100, u=7993461 

Puedo entender que el primero ( lld ) se imprimió como basura porque el printf intenta imprimir 8 bytes (para signed long long como lo indica lld ) cuando solo hay disponibles 4 bytes de temp variable. Pero no entiendo por qué el último identificador 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 unsigned int tiene unsigned int (que tiene 4 bytes firmados para mi i386).

Ahora, hice un pequeño ajuste con la línea printf :

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

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

 ld=100, u=100, lld=34331653576851556 

¿Alguien puede por favor ayudarme a entender qué es exactamente lo que me falta aquí?

¡Muchas gracias por cualquier ayuda!

[nota al margen: Intenté cambiar la optimización usando la etiqueta gcc -O[0,2] on / off sin ninguna diferencia en la observación.]

Eso es porque lo que ha empujado en la stack son 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 absorbe el tercero y lld lo que sea que esté en la stack después de eso, lo que realmente podría ser cualquier cosa.

Cuando cambia el orden de los especificadores de formato en la cadena, funciona de manera diferente porque el ld absorbe el primer valor de 32 bits, el u chupa el segundo y el lld absorbe el tercero más lo que sea que esté en la stack después ese. Es por eso que obtienes diferentes valores, es un problema de alineación / disponibilidad de datos.

Puedes ver esto en acción con el primer valor. 429496729700 es igual a (4294967296 + 1) * 100 , es decir, (2 32 +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). | ? | / +-----+ 

Su código demuestra adecuadamente un 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, se debe utilizar lo siguiente:

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

Como recordatorio, recuerde que el especificador para size_t es z . Asi que:

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

Está pasando a printf la cantidad incorrecta de bytes. % lld requiere un número entero más grande, en su caso la forma en que% lld tomó su argumento está completamente desordenado, ya que esperaría un valor de 64 bits.