2009-09-10 13 views
29

Tengo un código que imprime la cantidad de memoria utilizada por el programa. La línea es similar a esto:printf con sizeof en plataformas 32 vs 64: ¿cómo manejo el código de formato de manera independiente de la plataforma?

printf("The about of RAM used is %u", anIntVariable*sizeof(double)); 

donde anIntVariable es una variable int para el número de elementos de la doble matriz. De todos modos, en los sistemas de 32 bits nunca tuve ningún problema, pero en los sistemas de 64 bits, aparece una advertencia del compilador sobre el uso de "% u" para un entero largo sin signo. El uso de "% lu" como el código de formato corrige el problema en 64 bits pero provoca que el compilador se queje en 32 bits porque el tipo vuelve a unsigned int. Descubrí que, de hecho, sizeof (doble) devuelve un valor diferente en sistemas de 32 contra 64 bits. He encontrado algunas guías de páginas web para convertir código de 32 bits a 64 bits Pero prefiero tener un código que funcione en ambos en lugar de simplemente convertir de ida y vuelta.

¿Cómo escribo esta línea de una manera independiente de la plataforma? Sé de muchas maneras que podría hacerlo usando las directivas de preprocesador, pero eso parece un truco. Seguramente hay una manera elegante de la que no me estoy dando cuenta.

+2

Buena pregunta. – strager

+0

Buena pregunta de hecho. Eche un vistazo a http: // bytes.com/topic/c/answers/506972-64-bit-portability-size_t-printf-format-strings – adatapost

+1

Ver: http://stackoverflow.com/questions/1401526/use-printf-to-display-offt-nlinkt- sizet-and-others –

Respuesta

20

Los identificadores de printf portátiles se proporcionan en el archivo de inclusión inttypes.h.

Este archivo incluye muchos identificadores portátiles para su tiempo de ejecución específico. Para su ejemplo, quiere PRIuPTR, que significa "PR intf I dentor u nsigned con tamaño de hasta el tamaño de un puntero".

Su ejemplo será entonces:

printf("The amount of RAM used is %" PRIuPTR, anIntVariable*sizeof(double)); 

Resultados en Linux de 64 bits con GCC 4.3 (int anIntVariable = 1):

$ gcc test.c -m32 -o test && ./test 
The amount of RAM used is 8 
$ gcc test.c -o test && ./test 
The amount of RAM used is 8 

Para completarlo, hay identificadores para scanf también, cuyos prefijos son SCN .

+1

He editado mi respuesta con el código probado esta vez :) – LiraNuna

+0

Esta idea parece responder a mi pregunta. He estado programando en C durante varios años, pero mis problemas son normalmente prácticos, y rara vez se presentan cosas como la portabilidad. Estoy algo sorprendido de cómo la arquitectura juega un papel en una situación tan simple. Gracias, Lira y Thomas también, que tenían una solución de trabajo decente, pero esta parece ser la respuesta completa. –

+1

Esto aún no es portátil; asume 'sizeof (size_t) == sizeof (uintptr_t)', que no está garantizado. 'PRIuPTR' no funciona" hasta el tamaño de un puntero "; solo funciona con tipos enteros que son ** exactamente ** un 'uintptr_t' ancho. –

13

El valor de retorno de sizeof es un size_t. Si está utilizando un compilador compatible con C99, parece que puede usar %zd %zu para esto.

D'oh: %zu (sin firmar) por supuesto. Gracias, ony.

+1

'"% zu "' para 'size_t' y' "% zd" 'para' ssize_t', supongo;) – ony

+0

@ony sí, creo que es '% zu 'aquí (editado mi respuesta). Es un poco confuso porque el código está multiplicando un 'int' firmado con un' size_t' sin signo, cuyo resultado debe ser un tipo de entero sin signo. – wds

7

En primer lugar, debe coincidir con el "%" especificador con el tipo de datos real que desea imprimir. sizeof devuelve el tipo de datos size_t, y así como no debe intentar imprimir un flotante con un especificador "% d", no intente imprimir un size_t con "% u" o "% d" o cualquier cosa que no signifique realmente size_t.

Las otras respuestas han dado algunas buenas maneras de manejar esto con compiladores más nuevos ("% z" y PRIu32), pero la forma en que solíamos hacer esto era simplemente convertir size_t a unsigned long, y luego imprimirlo usando "% lu":

printf("The amount of RAM used is %lu", (unsigned long)(anIntVariable*sizeof(double))); 

Esto no funcionará en sistemas donde size_t es más ancha que larga, pero no sé de cualquiera de dichos sistemas, y no estoy seguro si la norma lo permite.

+0

Thomas. Tu respuesta parece funcionar mejor (bajo mi nivel actual de comprensión. Lo que causó el problema es que estaba asumiendo que hacer (size_t) heredaría el tipo de anIntVariable pero no es así. Mantendré la pregunta abrir por unos días más y luego marcar esto como la respuesta aceptada. Todavía tengo que encontrar el comportamiento de promoción de tipo de expresiones que contienen (size_t), que está relacionado con mi pregunta. –

+3

Tenga en cuenta que win64 es un sistema donde size_t es más amplio que un largo –

Cuestiones relacionadas