Como devo imprimir tipos como off_t e size_t?

148

Estou tentando imprimir tipos como off_te size_t. Qual é o espaço reservado correto para printf() isso é portátil ?

Ou existe uma maneira completamente diferente de imprimir essas variáveis?

Georg Schölly
fonte
2
@devin: Eu acredito que eu encontrei esse tipo durante o uso fopen, fseeketc. no Mac OS X. off_té utilizado para o deslocamento.
Georg Schölly 23/03

Respostas:

112

Você pode usar zpara size_t e tptrdiff_t como em

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

Mas minha página de manual diz que algumas bibliotecas mais antigas usavam um caractere diferente ze desencorajam o uso dele. No entanto, é padronizado (pelo padrão C99). Para aqueles intmax_te int8_tde stdint.he assim por diante, existem macros que você pode usar, como outra resposta disse:

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

Eles estão listados na página de manual inttypes.h.

Pessoalmente, eu apenas converteria os valores unsigned longou longgostaria que outra resposta recomendasse. Se você usa o C99, pode (e deve) transmitir para unsigned long longou long longusar os formatos %lluou %lld, respectivamente.

Johannes Schaub - litb
fonte
2
off_t é realmente um longo assinado no meu sistema.
Georg Schölly 27/02/09
2
Eu acho que a página de manual desencoraja o uso de Z (maiúsculo), que foi usado pelo libc5. Parece não desencorajar z (minúsculas).
Draemon
12
O uso %zdcom a size_té um comportamento indefinido devido à incompatibilidade de assinatura (C99 7.19.6.1 # 9). Deve ser %zu.
Jens
7
Bem, como imprimir off_t então?
31414 JohnyTex
3
@ Jens, eu não vejo como, %zdcom um size_tcomportamento indefinido, é obtido desse parágrafo ou de qualquer outro. De fato, a definição de %z# 7 permite explicitamente %dcom size_te o tipo assinado correspondente, e §6.2.5 # 9 permite explicitamente o uso de valores de tipos não assinados onde o tipo assinado correspondente é esperado, desde que o valor seja um valor não negativo válido do tipo assinado.
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 no padrão C99 ou a documentação mais conveniente do POSIX sobre códigos de formatação:

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

Se sua implementação não suportar esses códigos de formatação (por exemplo, porque você está no C89), você tem um problema, já que no AFAIK não há tipos de número inteiro no C89 que possuam códigos de formatação e que sejam tão grandes como esses tipos. Então, você precisa fazer algo específico da implementação.

Por exemplo, se o seu compilador tiver long longe a sua biblioteca padrão suportar %lld, você pode esperar com confiança que isso servirá no lugar de intmax_t. Mas, se isso não acontecer, você precisará recorrer long, o que falharia em algumas outras implementações porque é muito pequeno.

Steve Jessop
fonte
3
Esta é de longe a melhor resposta, eu teria me esquecido de usar% zu para size_t não assinado. E transmitir para intmax_t é uma ótima solução para qualquer que seja o off_t em qualquer plataforma.
Peter Cordes
2
O POSIX não garante que ssize_ttenha o mesmo tamanho que size_t, portanto, um código verdadeiramente portátil deve convertê-lo intmax_te imprimir com o %jdmesmo valor off_t.
Nwellnhof 30/09
off_t pode ter até o tamanho de comprimento e pode ser variável, dependendo da definição ... O Visual Studio avisa com isso também "aviso C4477: '_snprintf_s': a string de formato '% jd' requer um argumento do tipo '__int64', mas um argumento variado 1 tem o tipo 'off_t' "... Uma maneira verdadeiramente portátil é printf ("% lld \ n ", (long long) x);
Ericcurtin
5

Para a Microsoft, a resposta é diferente. O VS2013 é amplamente compatível com C99, mas "[h] os prefixos hh, j, z e comprimento não são suportados". Para size_t ", ou seja, __int32 não assinado em plataformas de 32 bits, __int64 não assinado em plataformas de 64 bits" use o prefixo I (maiúscula) com o especificador de tipo o, u, x ou X. Consulte a especificação de tamanho do VS2013

Quanto a off_t, é definido desde que VC \ include \ sys \ types.h.

NoBrassRing
fonte
Observe se off_té sempre o longque tornaria 32 bits (até o Windows de 64 bits usa 32 bits para long).
sourcejedi
3

Qual versão do C você está usando?

Em C90, a prática padrão é converter em assinado ou não assinado por muito tempo, conforme apropriado, e imprimir em conformidade. Eu já vi% z para size_t, mas Harbison e Steele não mencionam isso em printf () e, de qualquer forma, isso não ajudaria você com ptrdiff_t ou o que seja.

No C99, os vários tipos _t vêm com suas próprias macros printf, então algo como "Size is " FOO " bytes." eu não sei detalhes, mas isso faz parte de um formato numérico bastante grande que inclui o arquivo.

David Thornley
fonte
3

Você desejará usar as macros de formatação de inttypes.h.

Veja esta pergunta: Cadeia de caracteres de formato de plataforma cruzada para variáveis ​​do tipo size_t?

Michael Burr
fonte
Supondo que off_t seja um int assinado, do tamanho de um ponteiro (não sei qual é a definição precisa) como ptrdiff_t, você usaria PRIdPTR ou PRIiPTR.
227 Michael Burr
11
O off_ttipo é maior que um ponteiro em qualquer sistema de 32 bits que suporte arquivos grandes (que é a maioria dos sistemas de 32 bits atualmente).
Dietrich Epp
1
@ DietrichEpp: Na verdade, é pior do que isso; muitos sistemas de 32 bits possuem off_t e off64_t, e dependendo do recurso, as macros off_t podem realmente significar off64_t.
SamB 31/07
1

Olhando para man 3 printfLinux, OS X e OpenBSD, todos mostram suporte %zpara size_te %tpara ptrdiff_t(para C99), mas nenhum deles menciona off_t. Sugestões em geral geralmente oferecem a %uconversão para off_t, que é "correta o suficiente", tanto quanto eu sei (ambas unsigned inte off_tvariam de forma idêntica entre os sistemas de 64 e 32 bits).

dwc
fonte
1
Meu sistema (OS X) possui 32 unsigned inte 64 bits off_t. Portanto, o elenco causaria a perda de dados.
Dietrich Epp
-3

Vi este post pelo menos duas vezes, porque a resposta aceita é difícil de lembrar para mim (raramente uso zou jsinalizadores e eles parecem não ser independentes da plataforma ).

O padrão nunca indica claramente o tamanho exato dos dados size_t, por isso sugiro que você verifique primeiro o comprimento size_tna sua plataforma e selecione um deles:

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

E sugiro usar stdinttipos em vez de tipos de dados brutos para garantir a consistência.

elinx
fonte
1
Para C99 e C11, o padrão declara explicitamente que %zupode ser usado para imprimir size_tvalores. Definitivamente, não se deve recorrer ao uso de um especificador uint32_t/ uint64_tformat para imprimir um size_t, pois não há garantia de que esses tipos sejam compatíveis.
autistic
-4

Pelo que me lembro, a única maneira portátil de fazê-lo, é converter o resultado em "int longo não assinado" e usá-lo %lu.

printf("sizeof(int) = %lu", (unsigned long) sizeof(int));
James Curran
fonte
1
Deve ser "% lu", pois o modificador de comprimento deve vir antes da conversão.
dwc 25/02/09
1
off_t, por exemplo, é assinado por muito tempo.
Georg Schölly 27/02/09
@ GeorgSchölly - Então você encontrou um dilema, porque long longnão existe no padrão C ++ e, portanto, é inerentemente não portátil.
James Curran
-9

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

Shankar
fonte
Por que você deseja que o arquivo seja deslocado em octal?
poolieby