Tengo una variable de tipo size_t
y quiero imprimirla usando printf()
. ¿Qué especificador de formato utilizo para imprimirlo de forma portátil?
En la máquina de 32 bits, %u
parece correcto. Compilé con g++ -g -W -Wall -Werror -ansi -pedantic
, y no hubo advertencia. Pero cuando compilo ese código en una máquina de 64 bits, produce una advertencia.
size_t x = <something>;
printf("size = %u\n", x);
warning: format '%u' expects type 'unsigned int',
but argument 2 has type 'long unsigned int'
La advertencia desaparece, como se esperaba, si cambio eso a %lu
.
La pregunta es, ¿cómo puedo escribir el código, para que compile sin advertencia en máquinas de 32 y 64 bits?
Editar: Como solución alternativa, supongo que una respuesta podría ser "convertir" la variable en un número entero que sea lo suficientemente grande, digamos unsigned long
, e imprimir usando %lu
. Eso funcionaría en ambos casos. Estoy buscando si hay alguna otra idea.
unsigned long
es la mejor opción si su implementación de libc no admite elz
modificador; el estándar C99 recomiendasize_t
no tener un rango de conversión de enteros mayor quelong
, por lo que está razonablemente seguroRespuestas:
Usa el
z
modificador:fuente
printf()
modificadores de longitud del borrador C ++ 0x del 2009-11-09 (tabla 84 en la página 672)-pedantic
, deberá obtener un compilador que admita el borrador de C ++ 1x (muy poco probable), o deberá mover su código a un archivo compilado como C99. De lo contrario, su única opción es convertir sus variablesunsigned long long
y utilizarlas%llu
para ser lo más portátil posible.Parece que varía según el compilador que esté utilizando (blech):
%zu
(o%zx
, o%zd
pero eso lo muestra como si estuviera firmado, etc.)%Iu
(o%Ix
, o%Id
pero nuevamente está firmado, etc.), pero a partir de cl v19 (en Visual Studio 2015), Microsoft admite%zu
(consulte esta respuesta a este comentario )... y, por supuesto, si está usando C ++, puede usarlo
cout
como lo sugiere AraK .fuente
z
también es compatible con newlib (es decir, cygwin)%zd
es incorrecto parasize_t
; es correcto para el tipo con signo correspondiente asize_t
, pero ensize_t
sí mismo es un tipo sin signo.%zu
(y%zx
en caso de que quieran hexadecimal). Es cierto que%zu
probablemente debería haber sido el primero en la lista. Fijo.%zd
deba estar en la lista en absoluto. No se me ocurre ninguna razón para usar en%zd
lugar de%zu
imprimir unsize_t
valor. Ni siquiera es válido (tiene un comportamiento indefinido) si el valor excedeSIZE_MAX / 2
. (Para completar, puede mencionar%zo
para octal.)ssize_t
sea el tipo firmado correspondientesize_t
, por lo que no se garantiza que coincida"%zd"
. ( Probablemente esté en la mayoría de las implementaciones). Pubs.opengroup.org/onlinepubs/9699919799/basedefs/…Para C89, use
%lu
y emita el valor aunsigned long
:Para C99 y posterior, use
%zu
:fuente
unsigned long long
¿ Quizás ?uint64_t
luego usar laPRIu64
macro de inttypes.h, que contiene el especificador de formato.Ampliando la respuesta de Adam Rosenfield para Windows.
Probé este código con VS2013 Update 4 y VS2015 preview:
VS2015 generaron salidas binarias:
mientras que el generado por VS2013 dice:
Nota:
ssize_t
es una extensión POSIX ySSIZE_T
es algo similar en los tipos de datos de Windows , por lo tanto, agregué<BaseTsd.h>
referencia.Además, a excepción de los siguientes encabezados C99 / C11, todos los encabezados C99 están disponibles en la vista previa de VS2015:
Además, C11
<uchar.h>
ahora se incluye en la última vista previa.Para obtener más detalles, consulte esta lista antigua y la nueva para conocer la conformidad estándar.
fuente
Para aquellos que hablan de hacer esto en C ++, que no necesariamente admite las extensiones C99, les recomiendo encarecidamente el formato boost ::. Esto hace que la pregunta size_t type size sea discutible:
Como no necesita especificadores de tamaño en formato boost ::, puede preocuparse por cómo desea mostrar el valor.
fuente
%u
entonces.fuente
printf
especificador. Supongo que tienen algunas otras restricciones no establecidas que hacen que el uso destd::cout
un problema.printf
especificador".fuente
Como dijo AraK, la interfaz de transmisión de c ++ siempre funcionará de forma portátil.
Si desea C stdio, no hay una respuesta portátil a esto para ciertos casos de "portátil". Y se pone feo ya que, como has visto, elegir los indicadores de formato incorrectos puede generar una advertencia del compilador o dar una salida incorrecta.
C99 intentó resolver este problema con formatos inttypes.h como "%" PRIdMAX "\ n". Pero al igual que con "% zu", no todos admiten c99 (como MSVS antes de 2013). Hay archivos "msinttypes.h" flotando para lidiar con esto.
Si realiza una conversión a un tipo diferente, dependiendo de los indicadores, puede recibir una advertencia del compilador para el truncamiento o un cambio de signo. Si sigue esta ruta, elija un tipo de tamaño fijo relevante más grande. Uno sin signo largo largo y "% llu" o sin signo largo "% lu" debería funcionar, pero llu también puede ralentizar las cosas en un mundo de 32 bits como demasiado grande. (Editar: mi mac emite una advertencia en 64 bits para que% llu no coincida con size_t, aunque% lu,% llu y size_t son todos del mismo tamaño. Y% lu y% llu no son del mismo tamaño en mi MSVS2012. Entonces es posible que deba emitir + usar un formato que coincida).
Para el caso, puede ir con tipos de tamaño fijo, como int64_t. ¡Pero espera! Ahora volvemos a c99 / c ++ 11, y MSVS anterior falla nuevamente. ¡Además, también tiene moldes (por ejemplo, map.size () no es un tipo de tamaño fijo)!
Puede usar un encabezado o biblioteca de terceros, como boost. Si aún no está usando uno, es posible que no quiera inflar su proyecto de esa manera. Si está dispuesto a agregar uno solo para este problema, ¿por qué no usar transmisiones de c ++ o compilación condicional?
Por lo tanto, tiene que recurrir a transmisiones en c ++, compilación condicional, marcos de trabajo de terceros o algo portátil que funcione para usted.
fuente
¿Te avisará si pasas un entero sin signo de 32 bits a un formato% lu? Debería estar bien ya que la conversión está bien definida y no pierde ninguna información.
He oído que algunas plataformas definen macros en las
<inttypes.h>
que puede insertar en el literal de cadena de formato, pero no veo ese encabezado en mi compilador de Windows C ++, lo que implica que puede no ser multiplataforma.fuente
%lu
, debe convertir elsize_t
valor aunsigned long
. No hay conversión implícita (aparte de las promociones) para argumentosprintf
.C99 define "% zd", etc. para eso. (gracias a los comentaristas) No hay un especificador de formato portátil para eso en C ++: podría usar
%p
, lo que sería una palabra en estos dos escenarios, pero tampoco es una opción portátil, y da el valor en hexadecimal.Alternativamente, use algo de transmisión (por ejemplo, secuencia de cadena) o un reemplazo seguro de printf como Boost Format . Entiendo que este consejo es de uso limitado (y requiere C ++). (Hemos utilizado un enfoque similar para nuestras necesidades al implementar el soporte Unicode).
El problema fundamental para C es que printf usando puntos suspensivos no es seguro por diseño: necesita determinar el tamaño del argumento adicional a partir de los argumentos conocidos, por lo que no se puede arreglar para admitir "lo que sea que tenga". Entonces, a menos que su compilador implemente algunas extensiones propietarias, no tiene suerte.
fuente
z
modificador de tamaño es C estándar, pero algunas implementaciones de libc están estancadas en 1990 por varias razones (por ejemplo, Microsoft básicamente abandonó C en favor de C ++ y - más recientemente - C #)%zd
está mal, no está firmado, por lo que debería estarlo%zu
.En algunas plataformas y para algunos tipos, hay disponibles especificadores de conversión de printf específicos, pero a veces hay que recurrir a la conversión a tipos más grandes.
He documentado este problema complicado aquí, con un código de ejemplo: http://www.pixelbeat.org/programming/gcc/int_types/ y lo actualizo periódicamente con información sobre nuevas plataformas y tipos.
fuente
si desea imprimir el valor de un size_t como una cadena, puede hacer esto:
el resultado es:
número: 2337200120702199116
texto: ¡Vamos a pescar en lugar de sentarnos en nuestro pero!
Editar: releyendo la pregunta debido a los votos negativos, noté que su problema no es% llu o% I64d, pero el tipo size_t en diferentes máquinas ve esta pregunta https://stackoverflow.com/a/918909/1755797
http: // www. cplusplus.com/reference/cstdio/printf/
size_t es unsigned int en una máquina de 32 bits y unsigned long long int en 64bit
pero% ll siempre espera un unsigned long long int.
size_t varía en longitud en diferentes sistemas operativos, mientras que% llu es el mismo
fuente