¿Cómo debo imprimir tipos como off_t y size_t?


148

Estoy tratando de imprimir tipos como off_ty size_t. ¿Cuál es el marcador de posición correcto para printf() que sea portátil ?

¿O hay una forma completamente diferente de imprimir esas variables?


2
@devin: Creo que he encontrado ese tipo durante el uso fopen, fseek, etc en Mac OS X off_tse utiliza para el desplazamiento.
Georg Schölly

Respuestas:


112

Puede usar zpara size_t y tptrdiff_t como en

printf("%zu %td", size, ptrdiff);

Pero mi página de manual dice que alguna biblioteca más antigua usaba un carácter diferente zy desalienta su uso. Sin embargo, está estandarizado (según el estándar C99). Para aquellos intmax_ty int8_tde stdint.hy así sucesivamente, hay macros que puede usar, como dijo otra respuesta:

printf("value: %" PRId32, some_int32_t);
printf("value: %" PRIu16, some_uint16_t);

Se enumeran en la página de manual de inttypes.h.

Personalmente, simplemente emitiría los valores unsigned longo me longgustaría que otra respuesta me recomendara. Si usa C99, puede (y debería, por supuesto) emitir unsigned long longo long longusar los formatos %lluo %lldrespectivamente.


2
off_t es en realidad un signo firmado por mucho tiempo en mi sistema.
Georg Schölly

2
Creo que la página del manual desalienta el uso de Z (mayúscula) que fue utilizado por libc5. No parece desalentar z (minúsculas).
Draemon

12
El uso %zdcon a size_tes un comportamiento indefinido debido a la falta de coincidencia de firma (C99 7.19.6.1 # 9). Debe ser %zu.
Jens

77
Bueno, ¿cómo imprimir off_t entonces?
JohnyTex

3
@Jens No veo cómo %zdcon un size_tcomportamiento indefinido se obtiene de ese párrafo o de cualquier otro. De hecho, la definición de %zen # 7 permite explícitamente %dcon size_ty el tipo con signo correspondiente, y §6.2.5 # 9 permite explícitamente usar valores de tipos sin signo donde se espera el tipo con signo correspondiente, siempre que el valor sea un valor no negativo válido del tipo firmado.
Chortos-2

108

Para imprimir off_t:

printf("%jd\n", (intmax_t)x);

Para imprimir size_t:

printf("%zu\n", x);

Para imprimir ssize_t:

printf("%zd\n", x);

Consulte 7.19.6.1/7 en el estándar C99, o la documentación POSIX más conveniente de los códigos de formato:

http://pubs.opengroup.org/onlinepubs/009695399/functions/fprintf.html

Si su implementación no es compatible con esos códigos de formato (por ejemplo, porque está en C89), entonces tiene un pequeño problema, ya que AFAIK no hay tipos enteros en C89 que tengan códigos de formato y se garantice que sean tan grandes como estos tipos Por lo tanto, debe hacer algo específico de implementación.

Por ejemplo, si su compilador tiene long longy su biblioteca estándar es compatible %lld, puede esperar con confianza que sirva en lugar de intmax_t. Pero si no es así, tendrá que recurrir a long, lo que podría fallar en algunas otras implementaciones porque es demasiado pequeño.


3
Esta es, de lejos, la mejor respuesta, me habría olvidado de usar% zu para size_t sin signo. Y enviar a intmax_t es una gran solución para lo que sea off_t en cualquier plataforma.
Peter Cordes

2
POSIX no garantiza que ssize_ttenga el mismo tamaño size_t, por lo que un código verdaderamente portátil debería convertirlo intmax_te imprimirlo de la %jdmisma manera off_t.
nwellnhof

off_t puede tener un tamaño de largo largo y puede ser variable dependiendo de las definiciones ... Visual Studio advierte con esto también "advertencia C4477: '_snprintf_s': la cadena de formato '% jd' requiere un argumento de tipo '__int64', pero un argumento variable 1 tiene el tipo 'off_t' "... Una forma verdaderamente portátil es printf ("% lld \ n ", (long long) x);
ericcurtin

5

Para Microsoft, la respuesta es diferente. VS2013 es en gran medida compatible con C99 pero "[t] he hh, j, z y t prefijos de longitud no son compatibles". Para size_t ", es decir, __int32 sin signo en plataformas de 32 bits, __int64 sin signo en plataformas de 64 bits", utilice el prefijo I (ojo de mayúscula) con el especificador de tipo o, u, x o X. Consulte la especificación de tamaño VS2013

En cuanto a off_t, se define como largo en VC \ include \ sys \ types.h.


Tenga en cuenta que si off_tes siempre longeso lo haría de 32 bits (incluso Windows de 64 bits usa 32 bits para long).
sourcejedi

3

¿Qué versión de C estás usando?

En C90, la práctica estándar es emitir a largo con o sin signo, según corresponda, e imprimir en consecuencia. He visto% z para size_t, pero Harbison y Steele no lo mencionan en printf (), y en cualquier caso eso no lo ayudaría con ptrdiff_t o lo que sea.

En C99, los diversos tipos _t vienen con sus propias macros printf, por lo que algo como "Size is " FOO " bytes." no sé los detalles, pero eso es parte de un archivo de inclusión de formato numérico bastante grande.


3

Querrá usar las macros de formato de inttypes.h.

Consulte esta pregunta: ¿ Cadena de formato multiplataforma para variables de tipo size_t?


Suponiendo que off_t es un int firmado, del tamaño de un puntero (no sé cuál es la definición precisa) como ptrdiff_t, entonces usaría PRIdPTR o PRIiPTR.
Michael Burr

11
El off_ttipo es más grande que un puntero en cualquier sistema de 32 bits que admita archivos grandes (que actualmente es la mayoría de los sistemas de 32 bits).
Dietrich Epp

1
@DietrichEpp: En realidad, es peor que eso; muchos sistemas de 32 bits tienen off_t y off64_t, y dependiendo de las macros de la característica off_t puede significar off64_t.
SamB

1

En cuanto a man 3 printfLinux, OS X y OpenBSD, todos muestran soporte %zpara size_ty %tpara ptrdiff_t(para C99), pero ninguno de ellos menciona off_t. Las sugerencias en la naturaleza generalmente ofrecen la %uconversión para off_t, que es "lo suficientemente correcta" hasta donde puedo decir (ambas unsigned inty off_tvarían de manera idéntica entre los sistemas de 64 bits y 32 bits).


1
Mi sistema (OS X) tiene 32 bits unsigned inty 64 bits off_t. Por lo tanto, el reparto provocaría la pérdida de datos.
Dietrich Epp

-3

Vi esta publicación al menos dos veces, porque la respuesta aceptada es difícil de recordar para mí (rara vez uso zo jmarcas y parece que no son independientes de la plataforma ).

El estándar nunca dice claramente la longitud exacta de los datos size_t, por lo que le sugiero que primero verifique la longitud size_ten su plataforma y luego seleccione uno de ellos:

if sizeof(size_t) == 4 use PRIu32
if sizeof(size_t) == 8 use PRIu64

Y sugiero usar stdinttipos en lugar de tipos de datos sin procesar para la consistencia.


1
Para C99 y C11, el estándar establece explícitamente que %zuse puede usar para imprimir size_tvalores. Definitivamente no se debe recurrir al uso de un especificador de formato uint32_t/ uint64_tpara imprimir size_t, ya que no hay garantía de que esos tipos sean compatibles.
autista

-4

Según recuerdo, la única forma portátil de hacerlo es lanzar el resultado a "unsigned long int" y usarlo %lu.

printf("sizeof(int) = %lu", (unsigned long) sizeof(int));

1
Debe ser "% lu", ya que el modificador de longitud debe aparecer antes de la conversión.
dwc

1
off_t, por ejemplo, es un signo largo largo.
Georg Schölly

@ GeorgSchölly: entonces has encontrado un enigma, porque long longno existe en el estándar C ++ y, por lo tanto, es inherentemente no portátil.
James Curran

-9

use "% zo" para off_t. (octal) o "% zu" para decimal.


¿Por qué querrías que el archivo se compense en octal?
Poolie
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.